Синтаксис вложенных соединений в 1С: почему условия ПО идут в конце запроса?

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

При работе с языком запросов 1С:Предприятие программисты часто привыкают к линейной структуре описания связей: указали таблицу, тип соединения, следующую таблицу и сразу после этого — условие ПО. Однако иногда в чужом коде или после работы автоматического Конструктора запросов можно встретить конструкцию, которая кажется ошибочной: несколько ключевых слов СОЕДИНЕНИЕ идут подряд, а блок условий ПО смещен в самый конец. Разберем подробно, как работает такая логика и почему это не является ошибкой.

Анализ необычного синтаксиса

Рассмотрим ситуацию, с которой столкнулся автор вопроса. В коде был представлен фрагмент запроса, где после объявления первого соединения сразу следовало второе, без указания условий связи для первого. Проанализируем схематично, как это выглядит:


ВЫБРАТЬ
    *
ИЗ
    Таблица1 КАК Т1
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Таблица2 КАК Т2
    ЛЕВОЕ СОЕДИНЕНИЕ Таблица3 КАК Т3
    ПО Т2.Поле = Т3.Поле
    ПО Т1.Поле = Т2.Поле

На первый взгляд это кажется набором символов, но на самом деле перед нами — вложенное соединение. В языке запросов 1С порядок следования таблиц и условий ПО определяет иерархию объединения данных. Давайте выясним причину, по которой такая запись существует и как ее правильно читать.

Логика работы «стека» соединений

Для того чтобы понять этот синтаксис, воспользуемся правилом «последним пришел — первым ушел» (LIFO). Вложенные соединения работают следующим образом: система ищет ближайшее условие ПО для последних двух указанных таблиц. Рассмотрим по шагам процесс выполнения такого запроса:

  1. Программа видит блок из трех таблиц (Т1, Т2, Т3).
  2. Первое встреченное условие ПО (которое находится выше в тексте) относится к двум последним таблицам (Т2 и Т3). Сначала формируется результат их соединения.
  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-ПО), так как оно более прозрачно при отладке и анализе плана запроса СУБД.

Важное замечание по синтаксической ошибке в примере

Посмотрим на исходный пример из обсуждения:


ВЫБРАТЬ * ИЗ ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КодыШК КАК КодыШК

Важно отметить: если в тексте запроса сразу после слова ИЗ идет ВНУТРЕННЕЕ СОЕДИНЕНИЕ — это ошибка. У любого соединения всегда должен быть «левый» операнд (первая таблица). В примере автора, скорее всего, при копировании была утеряна основная таблица, например:


ВЫБРАТЬ * ИЗ Документ.ПриходныйОрдер КАК ПриходныйОрдер
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КодыШК КАК КодыШК...

Рекомендации по работе с вложенными соединениями

  1. Проверяйте логику: Если вы видите условия ПО, идущие подряд в конце блока ИЗ, помните о правиле обратного порядка (LIFO).
  2. Используйте временные таблицы: Вместо сложных вложенных соединений, которые трудно отлаживать, лучше вынести предварительные выборки во временные таблицы (МенеджерВременныхТаблиц). Это повышает читаемость и зачастую положительно сказывается на производительности.
  3. Осторожно с виртуальными таблицами: В примере упоминались ДвиженияТоваров.Обороты. Сочетание вложенных соединений с виртуальными таблицами может привести к неоптимальным планам запросов на уровне СУБД. Проанализируем ситуацию: иногда проще наложить фильтры внутри параметров виртуальной таблицы, чем городить сложные вложенные связи.
  4. Форматирование: Если вам все же необходимо использовать вложенное соединение, используйте отступы, чтобы визуально показать, какие таблицы группируются вместе.

Таким образом, мы выяснили, что «странный» порядок слов в запросе — это легитимный механизм платформы 1С для управления вложенностью связей. Знание этой особенности поможет вам правильно интерпретировать сложный код и избегать ошибок при ручном редактировании текстов запросов.

← На главную