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