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