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