Как отфильтровать записи в запросе 1С: от простого равенства до сложных условий

· 10 мин

Содержание

Условие ГДЕ в запросе 1С отбирает строки источника до группировки: ВЫБРАТЬ … ИЗ … ГДЕ <условие>. В результат попадают только записи, для которых условие истинно. Частое заблуждение — что ГДЕ можно ставить где угодно и фильтровать им суммы после группировки. Нет: агрегатные функции (СУММА, КОЛИЧЕСТВО) в ГДЕ запрещены, для них есть ИМЕЮЩИЕ.

Синтаксис условия ГДЕ — часть языка запросов платформы 8.3, поэтому он одинаково работает в любой конфигурации: БП, ЗУП, УТ, ERP. Различаются только имена таблиц и реквизитов.

Где стоит ГДЕ в тексте запроса и как пишется условие

Порядок предложений в запросе фиксирован. ГДЕ идёт сразу после ИЗ (и соединений), до группировки:

ВЫБРАТЬ
    Реализация.Ссылка,
    Реализация.Контрагент,
    Реализация.СуммаДокумента
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
    Реализация.Проведен = ИСТИНА
    И Реализация.Организация = &Организация
СГРУППИРОВАТЬ ПО …
ИМЕЮЩИЕ …
УПОРЯДОЧИТЬ ПО …

Что можно сравнивать в условии:

  • 🔹 поля источника — Реализация.Контрагент;
  • 🔹 параметры — &Организация, значение передаётся из кода через УстановитьПараметр;
  • 🔹 литералы — числа 100, строки "Москва", булево ИСТИНА/ЛОЖЬ, даты ДАТАВРЕМЯ(2026, 1, 1);
  • 🔹 предопределённые значения и перечисления — через ЗНАЧЕНИЕ(…);
  • 🔹 выражения — Цена * Количество > 10000, функции ГОД(), ПОДСТРОКА(), ВЫРАЗИТЬ().

Операторы сравнения: =, <>, <, >, <=, >=. Для булевого поля можно не писать = ИСТИНА: условие ГДЕ Реализация.Проведен работает так же.

Параметры из встроенного языка задаются так:

Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("Организация", Организация);
Выборка = Запрос.Выполнить().Выбрать();

Не склеивайте значения в текст запроса строками. Параметр безопаснее и быстрее: не нужно экранировать кавычки, СУБД переиспользует план.

Условие через конструктор запроса

В конструкторе (контекстное меню в тексте модуля → Конструктор запроса…) условия задаются на вкладке Условия. Перетащите поле в список — конструктор подставит Поле = &Поле и создаст параметр. Флажок Произвольное открывает поле для ручного выражения: туда пишут ИЛИ, В, ПОДОБНО и всё, что не укладывается в «поле = параметр». Несколько строк на вкладке объединяются через И.

И, ИЛИ, НЕ: как сочетать логические операторы

Простые условия склеиваются тремя операторами:

ОператорСмыслПример
Иоба условия истинныПроведен И СуммаДокумента > 0
ИЛИхотя бы одно истинноСклад = &Склад1 ИЛИ Склад = &Склад2
НЕотрицаниеНЕ ПометкаУдаления

Приоритет: сначала НЕ, затем И, затем ИЛИ. Из-за этого условие ниже работает не так, как кажется:

ГДЕ
    Реализация.Проведен
    И Реализация.Контрагент = &Покупатель1
    ИЛИ Реализация.Контрагент = &Покупатель2

Платформа читает его как (Проведен И Контрагент = &Покупатель1) ИЛИ Контрагент = &Покупатель2. В результат попадут и непроведённые документы второго покупателя. Правильно — скобки:

ГДЕ
    Реализация.Проведен
    И (Реализация.Контрагент = &Покупатель1
        ИЛИ Реализация.Контрагент = &Покупатель2)

Ставьте скобки вокруг каждой группы ИЛИ, даже если уверены в приоритетах. Через полгода запрос будет читать другой человек.

НЕ применяется к любому выражению: НЕ Контрагент В (&Исключения), НЕ Наименование ПОДОБНО "%тест%", НЕ (Сумма > 0 И Проведен).

Проверьте себя
Какие документы вернёт условие «Проведен И Склад = &А ИЛИ Склад = &Б»?
Чем отфильтровать группы, где сумма продаж больше 100 000?

Операторы В(), ПОДОБНО и МЕЖДУ в условиях

В — проверка по списку

В заменяет цепочку ИЛИ. Список можно задать тремя способами:

// перечисление значений
ГДЕ Реализация.Склад В (&Склад1, &Склад2)

// один параметр — массив или список значений
ГДЕ Реализация.Контрагент В (&СписокКонтрагентов)

// вложенный запрос
ГДЕ Реализация.Контрагент В
    (ВЫБРАТЬ Договоры.Владелец
     ИЗ Справочник.ДоговорыКонтрагентов КАК Договоры
     ГДЕ Договоры.ВидДоговора = ЗНАЧЕНИЕ(Перечисление.ВидыДоговоровКонтрагентов.СПокупателем))

Во вложенном запросе можно сравнивать сразу несколько полей: (Номенклатура, Склад) В (ВЫБРАТЬ Номенклатура, Склад ИЗ …). Количество и порядок полей должны совпадать.

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

Если в параметр &СписокКонтрагентов передан пустой массив, условие В не выполнится ни для одной строки — запрос вернёт пусто. Это не ошибка, но проверяйте массив до выполнения.

ПОДОБНО — поиск по шаблону строки

ПОДОБНО сравнивает строку с маской:

СимволЗначениеПример
%любое число любых символов"%болт%" — содержит «болт»
_ровно один символ"А_-01"
[…]один символ из набора или диапазона"[0-9]%" — начинается с цифры
[^…]один символ не из набора"[^A-Z]%"
ГДЕ Номенклатура.Наименование ПОДОБНО "%" + &Строка + "%"

Если в искомом тексте сами встречаются % или _, задайте спецсимвол: Наименование ПОДОБНО "%10~%%" СПЕЦСИМВОЛ "~" найдёт «скидка 10%». Регистр букв при сравнении в ПОДОБНО обычно не учитывается, но поведение может зависеть от СУБД — для точной проверки регистра такое условие не используйте.

МЕЖДУ — диапазон с границами

Сумма МЕЖДУ 1000 И 5000 равносильно Сумма >= 1000 И Сумма <= 5000. Обе границы включаются. МЕЖДУ работает с числами, датами и строками. Для дат это самый удобный способ задать период — с одной оговоркой про время, о ней ниже.

Фильтр по датам и периодам

Дата в 1С всегда хранит время. Документ от 31.03 в 15:40 — это 31.03.2026 15:40:00. Отсюда главная ловушка:

ГДЕ Реализация.Дата МЕЖДУ &Начало И &Конец

Если в &Конец передать 31.03 без времени (то есть 00:00:00), документы за весь последний день периода выпадут. Решение — нормализовать границы в коде:

Запрос.УстановитьПараметр("Начало", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("Конец", КонецДня(ДатаОкончания));

Или прямо в запросе: МЕЖДУ НАЧАЛОПЕРИОДА(&Начало, ДЕНЬ) И КОНЕЦПЕРИОДА(&Конец, ДЕНЬ).

Полезные функции для дат в условии:

  • 📅 НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ) и КОНЕЦПЕРИОДА(Дата, КВАРТАЛ) — границы периода; бывают ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД и другие.
  • 📅 ДОБАВИТЬКДАТЕ(&Дата, ДЕНЬ, -30) — сдвиг: «последние 30 дней».
  • 📅 РАЗНОСТЬДАТ(Дата, &ТекущаяДата, ДЕНЬ) > 45 — просрочка больше 45 дней.
  • 📅 ГОД(Дата), МЕСЯЦ(Дата), ДЕНЬНЕДЕЛИ(Дата) — части даты.
  • 📅 ДАТАВРЕМЯ(2026, 1, 1) — литерал даты; пустая дата — ДАТАВРЕМЯ(1, 1, 1).

Условие ГОД(Реализация.Дата) = 2025 даёт правильный результат, но не использует индекс по дате: СУБД посчитает функцию для каждой строки таблицы. Для больших таблиц пишите диапазоном: Дата МЕЖДУ ДАТАВРЕМЯ(2025,1,1) И ДАТАВРЕМЯ(2025,12,31,23,59,59).

Текущую дату в запрос не встроить функцией — её передают параметром: Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса()).

Ссылки, пустые значения и NULL в условии ГДЕ

Сравнение со ссылками и перечислениями

Ссылку сравнивают с параметром или с предопределённым значением через ЗНАЧЕНИЕ():

ГДЕ
    Товары.Номенклатура.ВидНоменклатуры = &ВидТовар
    И Реализация.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОперацийРеализацияТоваров.Товары)

Имя перечисления и значения смотрите в дереве конфигурации — в разных конфигурациях и релизах они различаются. ЗНАЧЕНИЕ() работает только внутри текста запроса и только с предопределёнными элементами, значениями перечислений, пустыми ссылками и точками маршрута.

Пустая ссылка

Незаполненное ссылочное поле в базе — это пустая ссылка своего типа, а не NULL:

ГДЕ Реализация.Договор = ЗНАЧЕНИЕ(Справочник.ДоговорыКонтрагентов.ПустаяСсылка)

Для полей разных типов пустые значения выглядят так:

Тип поляПустое значение в условии
Ссылка на справочникЗНАЧЕНИЕ(Справочник.Имя.ПустаяСсылка)
Ссылка на документЗНАЧЕНИЕ(Документ.Имя.ПустаяСсылка)
ПеречислениеЗНАЧЕНИЕ(Перечисление.Имя.ПустаяСсылка)
Строка""
Число0
ДатаДАТАВРЕМЯ(1, 1, 1)
Составной типНЕОПРЕДЕЛЕНО (если тип не выбран)

NULL

NULL появляется там, где данных нет вовсе: в левом соединении без пары, при обращении через точку к реквизиту, которого нет у объекта такого типа. Сравнение с NULL через = никогда не даёт истину. Нужен оператор ЕСТЬ NULL:

ГДЕ Остатки.КоличествоОстаток ЕСТЬ NULL       // товара нет в остатках
ГДЕ НЕ Цены.Цена ЕСТЬ NULL                     // цена найдена

Функция ЕСТЬNULL(Поле, 0) (слитно) — другое: она подменяет NULL значением. Удобна в условиях вида ЕСТЬNULL(Остатки.КоличествоОстаток, 0) < Заказ.Количество.

Тип ссылки: оператор ССЫЛКА

Для полей составного типа (регистратор, субконто) проверяйте тип оператором ССЫЛКА:

ГДЕ Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг

Как писать условия, чтобы запрос работал быстро

ГДЕ превращается в условие SQL-запроса к СУБД. Быстро работают условия, которые СУБД может проверить по индексу. Несколько правил практика:

  1. Условия виртуальных таблиц — в параметры, а не в ГДЕ. Для Остатки, Обороты, СрезПоследних отбор пишут в скобках таблицы:
    ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата, Склад = &Склад) КАК Остатки
    
    Так платформа отберёт данные до расчёта остатков. То же условие в ГДЕ сначала посчитает остатки по всем складам, а потом выкинет лишнее. Имя регистра в примере условное — посмотрите своё в конфигурации.
  2. Не оборачивайте индексированное поле функцией. ГОД(Дата) = 2025, ПОДСТРОКА(Код, 1, 3) = "000" — полный просмотр таблицы. Переписывайте на диапазоны.
  3. ПОДОБНО с % в начале маски индекс не использует. "болт%" — может по индексу, "%болт%" — всегда просмотр.
  4. ИЛИ по разным полям часто мешает СУБД выбрать индекс. Если запрос тяжёлый, разбейте его на два и соедините через ОБЪЕДИНИТЬ ВСЕ (следите за дублями, если строка подходит под оба условия).
  5. Разыменование через точку в составном типе. Регистратор.Контрагент при регистраторе из десяти типов документов порождает соединение с десятью таблицами. Сначала ограничьте тип: ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент.
  6. Индекс для реквизита. Если отбор по реквизиту справочника или документа частый, в свойствах реквизита в конфигураторе ставят Индексировать. В типовой конфигурации это изменение — через расширение или с учётом поддержки.

Строки неограниченной длины (реквизит «Строка» с длиной 0, например комментарий) нельзя напрямую сравнивать в условии — платформа выдаст ошибку. Приведите тип: ВЫРАЗИТЬ(Документ.Комментарий КАК СТРОКА(200)) = &Текст.

Необязательный отбор

Частая задача — отбирать по складу, только если склад выбран:

ГДЕ
    (&Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
        ИЛИ Реализация.Склад = &Склад)

Это работает, но ИЛИ мешает индексу. На больших таблицах лучше собирать текст запроса в коде: добавлять строку условия только при заполненном параметре. В отчётах на СКД для такого есть отборы пользователя — они сами добавляют условие в запрос.

Ошибки в условиях, которые не видно сразу

Синтаксические ошибки платформа покажет при выполнении. Опаснее те, после которых запрос молча возвращает не то.

  • ❌ Условие на правую таблицу левого соединения в ГДЕ. ЛЕВОЕ СОЕДИНЕНИЕ Цены … ГДЕ Цены.ВидЦены = &Вид отбросит товары без цены: у них в поле NULL, и условие ложно. Соединение фактически становится внутренним. Если нужны все товары, перенесите условие в ПО: ПО Цены.Номенклатура = Товары.Номенклатура И Цены.ВидЦены = &Вид.
  • ❌ Поле = NULL вместо Поле ЕСТЬ NULL. Условие синтаксически верно, но не вернёт ни одной строки.
  • ❌ NULL и пустая ссылка — одно и то же. Пустой договор в документе — это ПустаяСсылка, а не NULL. ЕСТЬ NULL его не найдёт.
  • ❌ Параметр не установлен. Если забыли УстановитьПараметр, запрос упадёт с ошибкой о незаданном параметре. Если установили, но не тем типом (строку вместо ссылки), — молча вернёт пусто.
  • ❌ Помеченные на удаление. Справочники выбираются вместе с помеченными элементами. Если они не нужны, добавьте НЕ Номенклатура.ПометкаУдаления.

Разбор сложного запроса с несколькими условиями

Задача: найти проведённые реализации за квартал по выбранной организации, где покупатель входит в группу «Оптовики», сумма от 50 000 до 500 000 ₽, а в комментарии нет пометки «возврат». Склад — необязательный отбор.

ВЫБРАТЬ
    Реализация.Ссылка КАК Документ,
    Реализация.Дата,
    Реализация.Контрагент,
    Реализация.СуммаДокумента
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
    Реализация.Проведен
    И Реализация.Организация = &Организация
    И Реализация.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, КВАРТАЛ)
                        И КОНЕЦПЕРИОДА(&Дата, КВАРТАЛ)
    И Реализация.Контрагент В ИЕРАРХИИ (&ГруппаОптовики)
    И Реализация.СуммаДокумента МЕЖДУ 50000 И 500000
    И НЕ ВЫРАЗИТЬ(Реализация.Комментарий КАК СТРОКА(200)) ПОДОБНО "%возврат%"
    И (&Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
        ИЛИ Реализация.Склад = &Склад)
УПОРЯДОЧИТЬ ПО
    Реализация.Дата

Что здесь сделано и почему:

  1. Сначала самые «узкие» условия — проведение, организация, период. Порядок в тексте на план СУБД не влияет, но так запрос легче читать.
  2. Период задан от одной даты: передайте любую дату квартала, функции сами найдут начало и конец с учётом времени.
  3. В ИЕРАРХИИ захватывает покупателей во вложенных подгруппах «Оптовиков».
  4. Комментарий приведён к строке фиксированной длины — иначе сравнение с маской выдаст ошибку.
  5. Необязательный склад взят в скобки, чтобы ИЛИ не «перебил» остальные условия через И.

Код вызова:

Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("Организация", Организация);
Запрос.УстановитьПараметр("Дата", ТекущаяДатаСеанса());
Запрос.УстановитьПараметр("ГруппаОптовики", ГруппаОптовики);
Запрос.УстановитьПараметр("Склад", Склад); // пустая ссылка — без отбора по складу
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Сообщить(СтрШаблон("%1 — %2", Выборка.Документ, Формат(Выборка.СуммаДокумента, "ЧДЦ=2")));
КонецЦикла;

Если в конфигурации у документа нет реквизита Склад в шапке (например, склад указан в строках), условие по складу переносят во вложенный запрос к табличной части или в соединение с ней.

Частые вопросы

Можно ли в ГДЕ сослаться на псевдоним поля из ВЫБРАТЬ?
Нет. Псевдоним после КАК в условии ГДЕ не виден. Повторите выражение целиком или вынесите расчёт во временную таблицу и фильтруйте уже её.
Можно ли использовать ГДЕ во вложенном запросе и во временной таблице?
Да. У каждого пакета запросов, временной таблицы и вложенного запроса своё предложение ГДЕ. Отбор лучше делать как можно раньше — в той таблице, откуда берутся данные.
Как отобрать записи, где строковое поле не заполнено?
Для строки фиксированной длины — Поле = "". Для строки неограниченной длины — ВЫРАЗИТЬ(Поле КАК СТРОКА(1)) = "".
Почему условие по полю табличной части дублирует документы?
Когда вы выбираете из Документ.Имя.Товары или соединяете с табличной частью, строк столько, сколько строк товаров. Используйте ВЫБРАТЬ РАЗЛИЧНЫЕ по ссылке или вложенный запрос Ссылка В (ВЫБРАТЬ Ссылка ИЗ … ГДЕ …).
Учитывает ли ПОДОБНО регистр букв?
Как правило, нет, но результат может зависеть от СУБД и её настроек сортировки. Для строгой проверки регистра сравнивайте значения после выборки во встроенном языке.