При решении учетных задач (например, при контроле возврата подписанных первичных документов или расчете мотивации менеджеров по закрытым сделкам) часто возникает необходимость хранить пользовательские реквизиты. В типовых конфигурациях 1С для этого используется механизм дополнительных сведений и регистр сведений ДополнительныеСведения.
Так как в регистре ДополнительныеСведения каждое свойство записывается отдельной строкой в разрезе объекта, прямое обращение к регистру возвращает несколько записей на один и тот же документ. Разберем по шагам, как правильно составить текст запроса, чтобы объединить статус и дату статуса в одну результирующую строку по каждому документу реализации.
Наиболее наглядным и распространенным способом является многократное присоединение таблицы РегистрСведений.ДополнительныеСведения с отбором по конкретному свойству в условиях связи.
Рассмотрим структуру такого запроса:
ВЫБРАТЬ
Реализация.Ссылка КАК Документ,
Реализация.Контрагент КАК Контрагент,
Реализация.Ответственный КАК Ответственный,
ВЫРАЗИТЬ(ДопСведДата.Значение КАК ДАТА) КАК ДатаСтатуса,
ВЫРАЗИТЬ(ДопСведСтатус.Значение КАК Справочник.ЗначенияСвойствОбъектов) КАК Статус
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДопСведДата
ПО (ДопСведДата.Объект = Реализация.Ссылка)
И (ДопСведДата.Свойство = &СвойствоДата)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДопСведСтатус
ПО (ДопСведСтатус.Объект = Реализация.Ссылка)
И (ДопСведСтатус.Свойство = &СвойствоСтатус)
ГДЕ
Реализация.Проведен = ИСТИНА
Проанализируем ключевые особенности этого подхода:
ДопСвед.Свойство = &Свойство... обязательно указываются в секции ПО, а не в секции ГДЕ. Если поместить эти условия в ГДЕ, строки документов, у которых еще не заполнены дополнительные сведения, будут отсечены, а левое соединение неявно превратится во внутреннее.Значение регистра имеет составной тип. Функция ВЫРАЗИТЬ(...) позволяет СУБД корректно типизировать результирующую колонку и задействовать индексы.Если для одного объекта требуется получить большое количество дополнительных сведений или необходимо минимизировать количество соединений одной и той же физической таблицы, можно применить подход с агрегацией через МАКСИМУМ.
Посмотрим на пример реализации через временную таблицу:
ВЫБРАТЬ
ДопСвед.Объект КАК Объект,
ВЫРАЗИТЬ(ДопСвед.Значение КАК Справочник.ЗначенияСвойствОбъектов) КАК Статус,
ДАТАВРЕМЯ(1, 1, 1) КАК ДатаСтатуса
ПОМЕСТИТЬ ВТ_Сведения
ИЗ
РегистрСведений.ДополнительныеСведения КАК ДопСвед
ГДЕ
ДопСвед.Свойство = &СвойствоСтатус
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДопСвед.Объект,
ЗНАЧЕНИЕ(Справочник.ЗначенияСвойствОбъектов.ПустаяСсылка),
ВЫРАЗИТЬ(ДопСвед.Значение КАК ДАТА)
ИЗ
РегистрСведений.ДополнительныеСведения КАК ДопСвед
ГДЕ
ДопСвед.Свойство = &СвойствоДата
;
ВЫБРАТЬ
ВТ.Объект КАК Документ,
МАКСИМУМ(ВТ.Статус) КАК Статус,
МАКСИМУМ(ВТ.ДатаСтатуса) КАК ДатаСтатуса
ПОМЕСТИТЬ ВТ_СвернутыеСведения
ИЗ
ВТ_Сведения КАК ВТ
СГРУППИРОВАТЬ ПО
ВТ.Объект
ИНДЕКСИРОВАТЬ ПО
Документ
;
ВЫБРАТЬ
Реализация.Ссылка КАК Документ,
Реализация.Контрагент КАК Контрагент,
ЕСТЬNULL(Сведения.Статус, ЗНАЧЕНИЕ(Справочник.ЗначенияСвойствОбъектов.ПустаяСсылка)) КАК Статус,
ЕСТЬNULL(Сведения.ДатаСтатуса, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаСтатуса
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_СвернутыеСведения КАК Сведения
ПО (Сведения.Документ = Реализация.Ссылка)
ГДЕ
Реализация.Проведен = ИСТИНА
Если задача требует получения не только шапки реализации, но и детализации по номенклатуре из табличных частей Товары и Услуги, важно избегать разыменования полей шапки через точку (например, ДокументТовары.Ссылка.Контрагент), так как это приводит к лишним соединениям.
Разберем оптимальную структуру запроса для выборки строк документа вместе с дополнительными сведениями:
ВЫБРАТЬ
ТЧ.Ссылка КАК Ссылка,
ТЧ.Номенклатура КАК Номенклатура,
ТЧ.Количество КАК Количество,
ТЧ.Цена КАК Цена,
ТЧ.Сумма КАК Сумма
ПОМЕСТИТЬ ВТ_Строки
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК ТЧ
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ТЧ.Ссылка,
ТЧ.Номенклатура,
ТЧ.Количество,
ТЧ.Цена,
ТЧ.Сумма
ИЗ
Документ.РеализацияТоваровУслуг.Услуги КАК ТЧ
ИНДЕКСИРОВАТЬ ПО
Ссылка
;
ВЫБРАТЬ
Строки.Ссылка КАК Документ,
Реализация.Контрагент КАК Контрагент,
Реализация.Ответственный КАК Ответственный,
Строки.Номенклатура КАК Номенклатура,
Строки.Количество КАК Количество,
Строки.Цена КАК Цена,
Строки.Сумма КАК Сумма,
ВЫРАЗИТЬ(ДопСведДата.Значение КАК ДАТА) КАК ДатаСтатуса,
ВЫРАЗИТЬ(ДопСведСтатус.Значение КАК Справочник.ЗначенияСвойствОбъектов) КАК Статус
ИЗ
ВТ_Строки КАК Строки
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализация
ПО (Строки.Ссылка = Реализация.Ссылка)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДопСведДата
ПО (ДопСведДата.Объект = Строки.Ссылка)
И (ДопСведДата.Свойство = &СвойствоДата)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДопСведСтатус
ПО (ДопСведСтатус.Объект = Строки.Ссылка)
И (ДопСведСтатус.Свойство = &СвойствоСтатус)
ГДЕ
Реализация.Проведен = &Проведен
И (ВЫРАЗИТЬ(ДопСведДата.Значение КАК ДАТА) МЕЖДУ &ДатаСтатусаНач И &ДатаСтатусаКон)
И (ВЫРАЗИТЬ(ДопСведСтатус.Значение КАК Справочник.ЗначенияСвойствОбъектов) = &ЗначениеСтатуса)
Выясним, какие альтернативные архитектурные решения можно использовать, чтобы упростить выборку и обеспечить целостность данных:
СостоянияОригиналовПервичныхДокументов. Он автоматически фиксирует состояние, автора и дату изменения без необходимости настройки пользовательских доп. сведений.Документ и ресурсами Статус и ДатаСтатуса обеспечивает атомарность записи (нельзя сменить статус, не обновив дату) и исключает необходимость многократных соединений в отчетах.