Как избежать задвоения строк при запросе к табличной части документа из регистра сведений в 1С?

Программист 1С v8.3 (Управляемые формы)
← На главную

При разработке отчетов и обработок в платформе 1С разработчики часто сталкиваются с ситуацией, когда простой с виду запрос к регистру сведений и табличной части документа начинает возвращать дублирующиеся строки. Рассмотрим подробно причину возникновения такой проблемы и разберем по шагам способы ее корректного решения.

В чем причина размножения строк в запросе?

Проанализируем механику работы языка запросов 1С при выполнении оператора ЛЕВОЕ СОЕДИНЕНИЕ. Если в регистре сведений измерение ИсточникЗаписи содержит ссылку на документ, а мы соединяем этот регистр с табличной частью данного документа исключительно по полю ссылки:

ПО ЗаписиSAP.ИсточникЗаписи = Viper_ТаможеннаяДекларацияАвтомобили.Ссылка

Происходит декартово произведение строк. Если в табличной части документа содержится, например, 7 строк, то для одной записи регистра платформа вернет ровно 7 одинаковых по шапке записей — по одной на каждую строку из табличной части документа.

Способ 1. Соединение по уникальной аналитике строки

Если каждая запись регистра сведений соответствует конкретной строке табличной части документа, необходимо добавить в условие связи (секция ПО) дополнительное поле идентификации — например, серийный номер, номенклатуру или артикул.

Разберем пример запроса, в котором добавлено связывание по серийному номеру автомобиля:


ВЫБРАТЬ
	Записи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.ЗаписьВыгружена

Способ 2. Ограничение по номеру строки табличной части

Если из всего документа требуется получить значение только из первой попавшейся строки табличной части, в условие соединения можно явно добавить фильтр по реквизиту НомерСтроки:


ПО ЗаписиSAP.ИсточникЗаписи = Viper_ТаможеннаяДекларацияАвтомобили.Ссылка
	И Viper_ТаможеннаяДекларацияАвтомобили.НомерСтроки = 1

Это гарантирует, что из табличной части подтянется ровно одна строчка и общее количество записей не увеличится.

Важные нюансы: обработка NULL и составных типов

При составлении подобных запросов важно учитывать еще два критических момента:

  1. Обработка значений NULL: Поле правого источника данных при левом соединении может принимать значение NULL, если совпадение не найдено. Прямое сравнение с датой в условных операторах ВЫБОР КОГДА вернет ложь. Всегда оборачивайте реквизиты присоединенной таблицы в функцию ЕСТЬNULL().
  2. Ограничение типов для составных реквизитов: Если реквизиты ИсточникЗаписи или Партия имеют составной тип данных, прямое обращение через точку (например, Партия.ВхДокДата) вызывает создание множественных неявных соединений на уровне СУБД. В таких случаях следует применять конструкцию ВЫРАЗИТЬ(Таблица.Партия КАК Документ.ПоступлениеТоваровИУслуг).
← На главную