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