Как отфильтровать записи в запросе 1С: от простого равенства до сложных условий
Содержание
Условие ГДЕ в запросе 1С отбирает строки источника до группировки: ВЫБРАТЬ … ИЗ … ГДЕ <условие>. В результат попадают только записи, для которых условие истинно. Частое заблуждение — что ГДЕ можно ставить где угодно и фильтровать им суммы после группировки. Нет: агрегатные функции (СУММА, КОЛИЧЕСТВО) в ГДЕ запрещены, для них есть ИМЕЮЩИЕ.
Синтаксис условия ГДЕ — часть языка запросов платформы 8.3, поэтому он одинаково работает в любой конфигурации: БП, ЗУП, УТ, ERP. Различаются только имена таблиц и реквизитов.
Где стоит ГДЕ в тексте запроса и как пишется условие
Порядок предложений в запросе фиксирован. ГДЕ идёт сразу после ИЗ (и соединений), до группировки:
ВЫБРАТЬ
Реализация.Ссылка,
Реализация.Контрагент,
Реализация.СуммаДокумента
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Проведен = ИСТИНА
И Реализация.Организация = &Организация
СГРУППИРОВАТЬ ПО …
ИМЕЮЩИЕ …
УПОРЯДОЧИТЬ ПО …
Что можно сравнивать в условии:
- 🔹 поля источника —
Реализация.Контрагент; - 🔹 параметры —
&Организация, значение передаётся из кода черезУстановитьПараметр; - 🔹 литералы — числа
100, строки"Москва", булевоИСТИНА/ЛОЖЬ, датыДАТАВРЕМЯ(2026, 1, 1); - 🔹 предопределённые значения и перечисления — через
ЗНАЧЕНИЕ(…); - 🔹 выражения —
Цена * Количество > 10000, функцииГОД(),ПОДСТРОКА(),ВЫРАЗИТЬ().
Операторы сравнения: =, <>, <, >, <=, >=. Для булевого поля можно не писать = ИСТИНА: условие ГДЕ Реализация.Проведен работает так же.
Параметры из встроенного языка задаются так:
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("Организация", Организация);
Выборка = Запрос.Выполнить().Выбрать();
Не склеивайте значения в текст запроса строками. Параметр безопаснее и быстрее: не нужно экранировать кавычки, СУБД переиспользует план.
Условие через конструктор запроса
В конструкторе (контекстное меню в тексте модуля → Конструктор запроса…) условия задаются на вкладке Условия. Перетащите поле в список — конструктор подставит Поле = &Поле и создаст параметр. Флажок Произвольное открывает поле для ручного выражения: туда пишут ИЛИ, В, ПОДОБНО и всё, что не укладывается в «поле = параметр». Несколько строк на вкладке объединяются через И.
И, ИЛИ, НЕ: как сочетать логические операторы
Простые условия склеиваются тремя операторами:
| Оператор | Смысл | Пример |
|---|---|---|
И | оба условия истинны | Проведен И СуммаДокумента > 0 |
ИЛИ | хотя бы одно истинно | Склад = &Склад1 ИЛИ Склад = &Склад2 |
НЕ | отрицание | НЕ ПометкаУдаления |
Приоритет: сначала НЕ, затем И, затем ИЛИ. Из-за этого условие ниже работает не так, как кажется:
ГДЕ
Реализация.Проведен
И Реализация.Контрагент = &Покупатель1
ИЛИ Реализация.Контрагент = &Покупатель2
Платформа читает его как (Проведен И Контрагент = &Покупатель1) ИЛИ Контрагент = &Покупатель2. В результат попадут и непроведённые документы второго покупателя. Правильно — скобки:
ГДЕ
Реализация.Проведен
И (Реализация.Контрагент = &Покупатель1
ИЛИ Реализация.Контрагент = &Покупатель2)
Ставьте скобки вокруг каждой группы ИЛИ, даже если уверены в приоритетах. Через полгода запрос будет читать другой человек.
НЕ применяется к любому выражению: НЕ Контрагент В (&Исключения), НЕ Наименование ПОДОБНО "%тест%", НЕ (Сумма > 0 И Проведен).
Операторы В(), ПОДОБНО и МЕЖДУ в условиях
В — проверка по списку
В заменяет цепочку ИЛИ. Список можно задать тремя способами:
// перечисление значений
ГДЕ Реализация.Склад В (&Склад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-запроса к СУБД. Быстро работают условия, которые СУБД может проверить по индексу. Несколько правил практика:
- Условия виртуальных таблиц — в параметры, а не в ГДЕ. Для
Остатки,Обороты,СрезПоследнихотбор пишут в скобках таблицы:
Так платформа отберёт данные до расчёта остатков. То же условие в ГДЕ сначала посчитает остатки по всем складам, а потом выкинет лишнее. Имя регистра в примере условное — посмотрите своё в конфигурации.ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата, Склад = &Склад) КАК Остатки - Не оборачивайте индексированное поле функцией.
ГОД(Дата) = 2025,ПОДСТРОКА(Код, 1, 3) = "000"— полный просмотр таблицы. Переписывайте на диапазоны. - ПОДОБНО с
%в начале маски индекс не использует."болт%"— может по индексу,"%болт%"— всегда просмотр. - ИЛИ по разным полям часто мешает СУБД выбрать индекс. Если запрос тяжёлый, разбейте его на два и соедините через
ОБЪЕДИНИТЬ ВСЕ(следите за дублями, если строка подходит под оба условия). - Разыменование через точку в составном типе.
Регистратор.Контрагентпри регистраторе из десяти типов документов порождает соединение с десятью таблицами. Сначала ограничьте тип:ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент. - Индекс для реквизита. Если отбор по реквизиту справочника или документа частый, в свойствах реквизита в конфигураторе ставят
Индексировать. В типовой конфигурации это изменение — через расширение или с учётом поддержки.
Строки неограниченной длины (реквизит «Строка» с длиной 0, например комментарий) нельзя напрямую сравнивать в условии — платформа выдаст ошибку. Приведите тип: ВЫРАЗИТЬ(Документ.Комментарий КАК СТРОКА(200)) = &Текст.
Необязательный отбор
Частая задача — отбирать по складу, только если склад выбран:
ГДЕ
(&Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
ИЛИ Реализация.Склад = &Склад)
Это работает, но ИЛИ мешает индексу. На больших таблицах лучше собирать текст запроса в коде: добавлять строку условия только при заполненном параметре. В отчётах на СКД для такого есть отборы пользователя — они сами добавляют условие в запрос.
Ошибки в условиях, которые не видно сразу
Синтаксические ошибки платформа покажет при выполнении. Опаснее те, после которых запрос молча возвращает не то.
- ❌ Условие на правую таблицу левого соединения в ГДЕ.
ЛЕВОЕ СОЕДИНЕНИЕ Цены … ГДЕ Цены.ВидЦены = &Видотбросит товары без цены: у них в поле NULL, и условие ложно. Соединение фактически становится внутренним. Если нужны все товары, перенесите условие вПО:ПО Цены.Номенклатура = Товары.Номенклатура И Цены.ВидЦены = &Вид. - ❌
Поле = NULLвместоПоле ЕСТЬ NULL. Условие синтаксически верно, но не вернёт ни одной строки. - ❌ NULL и пустая ссылка — одно и то же. Пустой договор в документе — это
ПустаяСсылка, а не NULL.ЕСТЬ NULLего не найдёт. - ❌ Параметр не установлен. Если забыли
УстановитьПараметр, запрос упадёт с ошибкой о незаданном параметре. Если установили, но не тем типом (строку вместо ссылки), — молча вернёт пусто. - ❌ Помеченные на удаление. Справочники выбираются вместе с помеченными элементами. Если они не нужны, добавьте
НЕ Номенклатура.ПометкаУдаления.
Разбор сложного запроса с несколькими условиями
Задача: найти проведённые реализации за квартал по выбранной организации, где покупатель входит в группу «Оптовики», сумма от 50 000 до 500 000 ₽, а в комментарии нет пометки «возврат». Склад — необязательный отбор.
ВЫБРАТЬ
Реализация.Ссылка КАК Документ,
Реализация.Дата,
Реализация.Контрагент,
Реализация.СуммаДокумента
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Проведен
И Реализация.Организация = &Организация
И Реализация.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, КВАРТАЛ)
И КОНЕЦПЕРИОДА(&Дата, КВАРТАЛ)
И Реализация.Контрагент В ИЕРАРХИИ (&ГруппаОптовики)
И Реализация.СуммаДокумента МЕЖДУ 50000 И 500000
И НЕ ВЫРАЗИТЬ(Реализация.Комментарий КАК СТРОКА(200)) ПОДОБНО "%возврат%"
И (&Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
ИЛИ Реализация.Склад = &Склад)
УПОРЯДОЧИТЬ ПО
Реализация.Дата
Что здесь сделано и почему:
- Сначала самые «узкие» условия — проведение, организация, период. Порядок в тексте на план СУБД не влияет, но так запрос легче читать.
- Период задан от одной даты: передайте любую дату квартала, функции сами найдут начало и конец с учётом времени.
В ИЕРАРХИИзахватывает покупателей во вложенных подгруппах «Оптовиков».- Комментарий приведён к строке фиксированной длины — иначе сравнение с маской выдаст ошибку.
- Необязательный склад взят в скобки, чтобы ИЛИ не «перебил» остальные условия через И.
Код вызова:
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("Организация", Организация);
Запрос.УстановитьПараметр("Дата", ТекущаяДатаСеанса());
Запрос.УстановитьПараметр("ГруппаОптовики", ГруппаОптовики);
Запрос.УстановитьПараметр("Склад", Склад); // пустая ссылка — без отбора по складу
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(СтрШаблон("%1 — %2", Выборка.Документ, Формат(Выборка.СуммаДокумента, "ЧДЦ=2")));
КонецЦикла;
Если в конфигурации у документа нет реквизита Склад в шапке (например, склад указан в строках), условие по складу переносят во вложенный запрос к табличной части или в соединение с ней.
Частые вопросы
Можно ли в ГДЕ сослаться на псевдоним поля из ВЫБРАТЬ?
Можно ли использовать ГДЕ во вложенном запросе и во временной таблице?
Как отобрать записи, где строковое поле не заполнено?
Поле = "". Для строки неограниченной длины — ВЫРАЗИТЬ(Поле КАК СТРОКА(1)) = "".Почему условие по полю табличной части дублирует документы?
Документ.Имя.Товары или соединяете с табличной частью, строк столько, сколько строк товаров. Используйте ВЫБРАТЬ РАЗЛИЧНЫЕ по ссылке или вложенный запрос Ссылка В (ВЫБРАТЬ Ссылка ИЗ … ГДЕ …).