Почему запрос в 1С выдает неполные данные при левом соединении

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При написании запросов в языке 1С разработчики часто сталкиваются с ситуацией, когда ЛЕВОЕ СОЕДИНЕНИЕ ведет себя как внутреннее (ВНУТРЕННЕЕ СОЕДИНЕНИЕ) и отсекает строки из основной таблицы. Рассмотрим, почему так происходит, как правильно накладывать условия на присоединяемые таблицы и как корректно выводить дополнительные данные, такие как температурный режим или штрихкоды.

Выясняем причину потери строк при левом соединении

Проанализируем классический запрос, с помощью которого отбирается номенклатура из документа ПеремещениеТоваров со сведениями о местах хранения и свойствах:


ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ
	ПеремещениеТоваровТовары.Номенклатура КАК Номенклатура,
	ПеремещениеТоваровТовары.Количество,
	ПеремещениеТоваровТовары.ЕдиницаИзмерения,
	ПеремещениеТоваровТовары.СерияНоменклатуры КАК СерияН,
	МестаХраненияНоменклатуры.МестоХранения КАК МестоХранения,
	ЗначенияСвойствОбъектов.Значение КАК ТемпРежим
ИЗ
	Документ.ПеремещениеТоваров.Товары КАК ПеремещениеТоваровТовары
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МестаХраненияНоменклатуры КАК МестаХраненияНоменклатуры
		ПО ПеремещениеТоваровТовары.Номенклатура = МестаХраненияНоменклатуры.Номенклатура
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
		ПО ПеремещениеТоваровТовары.Номенклатура = ЗначенияСвойствОбъектов.Объект
ГДЕ
	ПеремещениеТоваровТовары.Ссылка = &Ссылка
	И МестаХраненияНоменклатуры.Склад = &Склад
	И ЗначенияСвойствОбъектов.Свойство = &Свойство

Почему этот запрос отбрасывает позиции номенклатуры, для которых не указан температурный режим или место хранения?

При левом соединении, если в правой (присоединяемой) таблице нет записи для строки основной таблицы, на место полей правой таблицы подставляются значения NULL. Однако проверка условий в секции ГДЕ выполняется уже после того, как таблицы были соединены.

Когда мы пишем И ЗначенияСвойствОбъектов.Свойство = &Свойство в блоке ГДЕ, система проверяет условие для всех итоговых строк. Для элементов без свойств поле ЗначенияСвойствОбъектов.Свойство содержит NULL. Сравнение NULL = &Свойство возвращает ЛОЖЬ, и вся строка полностью отсекается из выборки.

То же самое касается условия МестаХраненияНоменклатуры.Склад = &Склад: если у позиции номенклатуры нет записи в регистре МестаХраненияНоменклатуры, то данная позиция также выпадет из результата.

Исправляем запрос: перенос условий в секцию ПО

Чтобы сохранить все строки из табличной части документа независимо от того, заполнены ли для них данные в регистрах сведений, наложим отбор на присоединяемые таблицы непосредственно в секции ПО соответствующего левого соединения.

Разберем по шагам правильное оформление запроса:


ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ
	ПеремещениеТоваровТовары.Номенклатура КАК Номенклатура,
	ПеремещениеТоваровТовары.Количество КАК Количество,
	ПеремещениеТоваровТовары.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
	ПеремещениеТоваровТовары.СерияНоменклатуры КАК СерияН,
	МестаХраненияНоменклатуры.МестоХранения КАК МестоХранения,
	ЗначенияСвойствОбъектов.Значение КАК ТемпРежим
ИЗ
	Документ.ПеремещениеТоваров.Товары КАК ПеремещениеТоваровТовары
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МестаХраненияНоменклатуры КАК МестаХраненияНоменклатуры
		ПО ПеремещениеТоваровТовары.Номенклатура = МестаХраненияНоменклатуры.Номенклатура
		И (МестаХраненияНоменклатуры.Склад = &Склад)
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
		ПО ПеремещениеТоваровТовары.Номенклатура = ЗначенияСвойствОбъектов.Объект
		И (ЗначенияСвойствОбъектов.Свойство = &Свойство)
ГДЕ
	ПеремещениеТоваровТовары.Ссылка = &Ссылка

Теперь условия по свойству и складу ограничивают только присоединяемые записи из регистров. Если совпадений нет, строка документа все равно остается в итоговой выборке, а в соответствующих полях возвращается NULL.

Замена незаполненных значений на текст по умолчанию

Если требуется выводить определенное текстовое описание вместо отсутствующего значения или NULL, воспользуемся функцией ЕСТЬNULL или оператором ВЫБОР КОГДА.

Простой пример замены NULL на строку:

ЕСТЬNULL(ЗначенияСвойствОбъектов.Значение, "Режим не задан") КАК ТемпРежим

Если же значение в регистре может присутствовать, но быть пустой ссылкой или неопределенным, надежнее применить такую конструкцию:


ВЫБОР
	КОГДА ЗначенияСвойствОбъектов.Значение ЕСТЬ NULL 
		ИЛИ ЗначенияСвойствОбъектов.Значение = ЗНАЧЕНИЕ(Справочник.ЗначенияСвойствОбъектов.ПустаяСсылка)
		ТОГДА "Режим не задан"
	ИНАЧЕ ЗначенияСвойствОбъектов.Значение
КОНЕЦ КАК ТемпРежим

Как правильно выводить штрихкоды без дублирования строк

Часто возникает необходимость добавить к строкам номенклатуры их штрихкоды. У одного элемента номенклатуры в регистре сведений Штрихкоды может быть несколько записей. Если выполнить простое ЛЕВОЕ СОЕДИНЕНИЕ с регистром штрихкодов, исходные строки документа продублируются столько раз, сколько штрихкодов заведено для позиции.

Использование агрегатных функций вида МАКСИМУМ(Количество) с группировками для решения этой проблемы приводит к ошибкам: если в документе одна и та же номенклатура указана в разных строках (например, с разными сериями или ценами), строки документа объединятся, а данные о количестве исказятся.

Рассмотрим два корректных подхода к выводу штрихкодов:

  1. Обход выборки с группировкой по номенклатуре (при построении печатных форм вручную). В запросе используется предложение ИТОГИ, после чего результат обрабатывается двумя вложенными циклами — по группировкам и по детальным записям:
    
    РезультатЗапроса = Запрос.Выполнить();
    ВыборкаНоменклатура = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    
    Пока ВыборкаНоменклатура.Следующий() Цикл
    	// Обработка уровня номенклатуры
    	ВыборкаДетальныеЗаписи = ВыборкаНоменклатура.Выбрать();
    	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    		// Получение детальных штрихкодов или серий
    	КонецЦикла;
    КонецЦикла;
    
  2. Получение штрихкодов отдельным запросом. Оптимальный способ при работе в коде BSL без использования СКД. Первым запросом выбираются строки документа с их реальным количеством и сериями. Вторым запросом выбираются штрихкоды для списка номенклатуры и помещаются в Соответствие, где ключом является Номенклатура, а значением — массив штрихкодов или скомпонованная строка. При выводе строки макета данные штрихкода подставляются из соответствия.

Следуя этим рекомендациям, вы сможете составлять корректные запросы в 1С, избегать потери данных при левом соединении и правильно выводить связанные сведения.

← На главную