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