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