К статье
Практический материал

Разработка и Конфигурация · 9 мин

Условие ГДЕ при внутреннем соединении в запросах 1С

Как правильно писать условие ГДЕ при внутреннем соединении в запросах 1С: синтаксис, фильтрация по виртуальным таблицам, типичные ошибки и примеры кода.

При написании запросов в системе 1С:Предприятие внутреннее соединение (ВНУТРЕННЕЕ СОЕДИНЕНИЕ) — самый частый способ объединить две таблицы, а секция ГДЕ — основной инструмент фильтрации результата. Проблема в том, что условие после соединения действует иначе, чем условие в параметрах виртуальной таблицы или в самой конструкции соединения, и неправильное размещение фильтра приводит либо к лишним записям, либо к потере нужных строк.

Внутреннее соединение возвращает только те пары записей, где условие связи выполнено в обеих таблицах. Если после этого добавить секцию ГДЕ, отбор применится уже к итоговому набору строк соединения. Это важно понимать: ГДЕ не влияет на то, какие таблицы участвуют в соединении, а лишь отсекает строки из готового результата.

Отдельная тонкость — работа с виртуальными таблицами регистров (Остатки, Обороты, СрезПоследних). Для них условие эффективнее передавать в параметры виртуальной таблицы, а не в секцию ГДЕ: тогда СУБД построит меньшую выборку ещё до соединения, и запрос выполнится заметно быстрее на больших объёмах данных.

Как работает внутреннее соединение с условием ГДЕ

Внутреннее соединение оставляет в результате только строки, для которых нашлась пара в обеих таблицах по условию связи, указанному после ключевого слова ПО. Если в левой таблице есть документ, а в правой нет соответствующей записи — строка в выборку не попадёт вообще, ещё до применения секции ГДЕ.

Секция ГДЕ выполняется логически после соединения. Это значит, что условие вида ГДЕ Товары.Количество > 0 отфильтрует строки, которые уже прошли соединение. Для внутреннего соединения перенос условия из ГДЕ в секцию ПО обычно даёт тот же результат, но для левого соединения разница принципиальна — поэтому важно выработать осознанную привычку, где размещать фильтр.

Базовый синтаксис запроса с соединением и условием

Типовая конструкция выглядит так: указываются поля выборки, затем источники с соединением, затем секция ГДЕ с отбором. Псевдонимы таблиц (КАК) обязательны для читаемости и позволяют однозначно ссылаться на поля.

ВЫБРАТЬ

Продажи.Номенклатура КАК Номенклатура,

Продажи.Количество КАК Количество,

Спр.Наименование КАК Наименование

ИЗ

РегистрНакопления.Продажи.Обороты(&Начало, &Конец, , ) КАК Продажи

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Спр

ПО Продажи.Номенклатура = Спр.Ссылка

ГДЕ

Спр.ЭтоГруппа = ЛОЖЬ

И Продажи.Количество > 0

В этом примере соединение связывает обороты регистра со справочником номенклатуры, а секция ГДЕ исключает группы справочника и нулевые количества. Порядок условий в ГДЕ объединяется операторами И, ИЛИ; для группировки используются скобки — без них приоритет И выше, чем ИЛИ, что часто становится источником ошибок.

bsl
ГДЕ
	(Спр.ЭтоГруппа = ЛОЖЬ ИЛИ Спр.Родитель = &Родитель)
	И Продажи.Количество > 0

Условие в параметрах виртуальной таблицы вместо ГДЕ

Виртуальные таблицы регистров накопления и сведений (Остатки, Обороты, СрезПоследних, СрезПервых) принимают параметры, в том числе условие отбора. Условие передаётся строкой в последнем параметре и выполняется на уровне построения виртуальной таблицы — до соединения с другими источниками.

РегистрНакопления.ТоварыНаСкладах.Остатки(

&Период,

Склад = &Склад

И Номенклатура В ИЕРАРХИИ (&Группа)) КАК Остатки

Такой подход сокращает объём данных, участвующих в соединении. Если отбор по складу перенести в секцию ГДЕ, виртуальная таблица сначала рассчитает остатки по всем складам, и только потом лишние строки будут отброшены — на крупной базе разница во времени выполнения ощутима.

Ограничение: в параметрах виртуальной таблицы нельзя ссылаться на поля других таблиц запроса — только на параметры запроса и константные выражения. Если фильтр зависит от данных второй таблицы, условие остаётся в секции ПО или ГДЕ.

Условие в секции ПО против секции ГДЕ

Для внутреннего соединения условие ПО А.Ссылка = Б.Ссылка И Б.ПометкаУдаления = ЛОЖЬ и аналогичное условие в ГДЕ дадут одинаковый набор строк. Однако размещение в ПО делает намерение явным: фильтр относится к правилам связи таблиц, а не к бизнес-логике отбора результата.

Практическое правило: условия, описывающие саму связь таблиц (равенство ключей, ограничение по виду движения), разумно держать в секции ПО; условия бизнес-отбора (период, организация, признак активности) — в ГДЕ или в параметрах виртуальной таблицы. Это упрощает чтение и сопровождение запроса.

Для левого соединения ситуация иная: условие по правой таблице в секции ГДЕ фактически превращает левое соединение во внутреннее, отсекая строки с NULL. Если нужно сохранить все строки левой таблицы, фильтр по правой помещайте именно в ПО.

Где размещать условие

Параметры виртуальной таблицы

Фильтр по полям регистра с параметрами запроса. Самый быстрый вариант, но без ссылок на другие таблицы.

Секция ПО

Условия связи таблиц и фильтры по правой таблице при левом соединении. Сохраняет семантику соединения.

Секция ГДЕ

Бизнес-отбор итогового результата, сложные условия, подзапросы, функции. Универсально, но применяется последним.

Типичные ошибки и как их избежать

Самая распространённая ошибка — фильтрация по полю правой таблицы в ГДЕ при левом соединении, когда разработчик ожидал получить все строки левой таблицы. Результат «теряет» записи, и это выглядит как загадочное исчезновение данных в отчёте.

Вторая частая проблема — забытые скобки при смешивании И и ИЛИ. Выражение А И Б ИЛИ В читается как (А И Б) ИЛИ В, а не как А И (Б ИЛИ В). Всегда расставляйте скобки явно, даже если текущий приоритет совпадает с замыслом.

Третья ошибка — сравнение с NULL. При соединениях поля могут принимать значение NULL, и условие Поле = &Значение отбросит такие строки. Для проверки на NULL используется конструкция Поле ЕСТЬ NULL или функция ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) в выборке.

Типичные ошибки
01
Фильтр по правой таблице в ГДЕ при левом соединении — пропадают строки левой таблицы без пары.
02
Отсутствие скобок при смешении И и ИЛИ — условие срабатывает не так, как задумано.
03
Сравнение с NULL через обычное равенство — строки с NULL молча исключаются.
04
Отбор по полю регистра в ГДЕ вместо параметров виртуальной таблицы — лишняя нагрузка на СУБД.
05
Соединение по неиндексированным полям без необходимости — резкое замедление запроса.

Проверка результата и производительность

После написания запроса проверьте его на контрольных данных: заведите тестовый случай, где часть строк левой таблицы не имеет пары в правой, и убедитесь, что результат соответствует ожиданиям. Для внутреннего соединения такие строки не должны появляться, для левого — должны с NULL в полях правой таблицы.

В консоли запросов полезно сравнить количество строк до и после добавления секции ГДЕ, а также время выполнения при переносе условия в параметры виртуальной таблицы. На больших таблицах разница видна сразу; на маленьких тестовых базах запросы могут казаться одинаково быстрыми, что маскирует проблему до выхода в рабочую базу.

Контрольные точки

Как проверить результат

Количество строк результата
Норма

Совпадает с ручным подсчётом на контрольном примере

Тревожный признак

Строк больше или меньше ожидаемого без объяснимой причины

Поля правой таблицы при левом соединении
Норма

NULL там, где нет пары, строки левой таблицы сохранены

Тревожный признак

Строки без пары исчезли — условие по правой таблице попало в ГДЕ

Время выполнения
Норма

Не растёт заметно при увеличении объёма данных

Тревожный признак

Резкий рост времени — проверьте параметры виртуальных таблиц и индексы

Значения NULL в отборах
Норма

Обработаны через ЕСТЬ NULL или ЕСТЬNULL

Тревожный признак

Строки с NULL теряются без намеренного решения разработчика

Порядок написания запроса
  1. 1
    Определите, какие таблицы связываются и по каким ключевым полям.
  2. 2
    Выберите тип соединения: внутреннее, если нужны только совпадения; левое — если нужны все строки левой таблицы.
  3. 3
    Перенесите отборы по полям регистров в параметры виртуальных таблиц.
  4. 4
    Условия связи и фильтры по правой таблице (при левом соединении) разместите в секции ПО.
  5. 5
    Бизнес-отбор результата запишите в секцию ГДЕ с явными скобками.
  6. 6
    Проверьте запрос на контрольных данных с записями без пары и со значениями NULL.

Часто задаваемые вопросы

Чем отличается условие в ПО от условия в ГДЕ при внутреннем соединении?

По результату — ничем: оба варианта отсекают строки, не удовлетворяющие условию. Разница в читаемости и переносимости: при смене типа соединения на левое условие в ГДЕ начнёт работать иначе, а условие в ПО сохранит исходный смысл.

Почему запрос с левым соединением вернул меньше строк, чем в левой таблице?

Скорее всего, в секции ГДЕ есть условие по полю правой таблицы. Для строк без пары это поле равно NULL, сравнение даёт ложь, и строка отбрасывается. Перенесите условие в секцию ПО или добавьте обработку NULL.

Можно ли использовать подзапрос в секции ГДЕ?

Да, например в конструкции Поле В (ВЫБРАТЬ ...). Но помните, что подзапрос в параметрах виртуальной таблицы недопустим — там только параметры запроса и простые выражения.

Как отфильтровать по списку значений в секции ГДЕ?

Используйте оператор В с параметром-списком: ГДЕ Номенклатура В (&СписокНоменклатуры). В коде параметру присваивается массив или список значений. Для иерархического отбора применяйте В ИЕРАРХИИ (&Группа).

Влияет ли порядок условий в ГДЕ на скорость запроса?

СУБД сама оптимизирует порядок вычисления условий, поэтому перестановка условий местами обычно ничего не меняет. На скорость влияет то, где размещён отбор: в параметрах виртуальной таблицы, в ПО или в ГДЕ, а также наличие индексов по полям соединения.

Как проверить поле на NULL в условии?

Используйте конструкцию Поле ЕСТЬ NULL или НЕ Поле ЕСТЬ NULL. Обычное сравнение Поле = NULL в языке запросов 1С не работает так, как ожидают разработчики, привыкшие к другим языкам.

Итог

Что важно запомнить

Секция ГДЕ при внутреннем соединении фильтрует уже готовый результат объединения. Отборы по регистрам переносите в параметры виртуальных таблиц, условия связи — в ПО, бизнес-отбор — в ГДЕ со скобками и корректной обработкой NULL.