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

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

Как писать условия в запросах 1С

Практическое руководство по условиям в запросах 1С: оператор ГДЕ, сравнения, В(), ПОДОБНО, NULL, агрегаты с ИМЕЮЩИЕ, ВЫБОР и типичные ошибки с примерами кода.

Условия в запросах 1С определяют, какие строки попадут в выборку и насколько быстро запрос выполнится. Корректно написанное условие сокращает выборку с миллионов записей до десятков нужных, а ошибка в нём либо возвращает пустой результат, либо заставляет сервер перебирать всю таблицу. Разница между «работает» и «работает правильно» здесь принципиальна, особенно на больших базах.

Язык запросов 1С похож на SQL, но имеет собственный синтаксис и ограничения. Условия можно задавать в секции ГДЕ, в секции ИМЕЮЩИЕ после группировки, в параметрах виртуальных таблиц и внутри конструкции ВЫБОР. Каждое место имеет своё назначение, и перенос условия из одного места в другое меняет как результат, так и производительность.

Материал ориентирован на разработчиков и консультантов, которые пишут запросы в конфигураторе или консоли запросов. Все примеры приведены на встроенном языке запросов 1С и подходят для типовых и самописных конфигураций.

Синтаксис секции ГДЕ и базовые операторы сравнения

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

ВЫБРАТЬ

Номенклатура.Ссылка КАК Товар,

Номенклатура.Наименование КАК Наименование

ИЗ

Справочник.Номенклатура КАК Номенклатура

ГДЕ

Номенклатура.Родитель = &Группа

И НЕ Номенклатура.ПометкаУдаления

Доступные операторы сравнения: =, <> (неравно), >, >=, <, <=. Логические связки — И, ИЛИ, НЕ. Приоритет стандартный: сначала НЕ, затем И, затем ИЛИ. При смешении И и ИЛИ всегда ставьте скобки явно, даже если приоритет вам известен: запрос ГДЕ А И Б ИЛИ В читается неоднозначно и часто становится источником ошибок при доработке.

Поля булевого типа (например, ПометкаУдаления) сравнивать с ИСТИНА избыточно: достаточно написать НЕ Номенклатура.ПометкаУдаления. Это короче и читается лучше.

Условия со списками, диапазонами и шаблонами

Оператор В() проверяет вхождение значения в список. Список можно передать параметром-массивом или списком значений — это самый частый сценарий при выборке по нескольким контрагентам или складам:

ГДЕ

Продажи.Контрагент В (&СписокКонтрагентов)

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

Оператор МЕЖДУ ... И ... проверяет попадание в диапазон включительно с обеих сторон. Для дат это удобно, но помните: если поле типа «дата и время», условие МЕЖДУ &Начало И &Конец с концом, равным началу дня, отсечёт все записи за последний день после 00:00:00. Безопаснее передавать конец дня (23:59:59) или использовать конструкцию с полуоткрытым интервалом.

Оператор ПОДОБНО выполняет поиск по шаблону: символ % — любая последовательность символов, _ — ровно один символ. Пример: Номенклатура.Артикул ПОДОБНО "АБЦ-%". Учтите два ограничения: поиск по ПОДОБНО с маской в начале строки не использует индекс и на больших таблицах работает медленно, а регистр сравнения зависит от настроек СУБД.

Работа с NULL и неопределёнными значениями

NULL в запросах 1С возникает при левом соединении, когда в присоединённой таблице нет подходящей строки, а также в полях составного типа. Принципиальный момент: NULL не равен ничему, включая сам себя. Условие ГДЕ Поле = NULL никогда не вернёт истину, а Поле <> NULL — тоже. Проверка выполняется только через специальный оператор:

ГДЕ

Остатки.Количество ЕСТЬ NULL

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

Типичная ловушка — сравнение результата левого соединения с нулём: разработчик пишет ГДЕ ЕСТЬNULL(Остатки.Количество, 0) = 0 и забывает, что такое условие не сможет использовать индекс по полю Количество. На небольших таблицах это некритично, на регистрах с миллионами записей — ощутимо.

Типичные ошибки
01
Сравнение с NULL через = вместо ЕСТЬ NULL — условие молча не срабатывает, строки теряются
02
Смешение И и ИЛИ без скобок — логика условия меняется, выборка становится шире или уже нужной
03
Незаполненный параметр-список для В() — запрос падает с ошибкой или возвращает пустой результат
04
Фильтр по виртуальной таблице в ГДЕ вместо параметров виртуальной таблицы — запрос считает итоги по всем данным, а потом отбрасывает лишнее

Условия в виртуальных таблицах регистров

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

ВЫБРАТЬ

Остатки.Номенклатура КАК Товар,

Остатки.КоличествоОстаток КАК Остаток

ИЗ

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

&Период,

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

И Номенклатура В (&СписокТоваров)) КАК Остатки

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

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

Сравнение вариантов

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

Итоги рассчитываются сразу по нужному срезу данных. Быстро, но доступно только для измерений и реквизитов регистра

Условие в секции ГДЕ

Универсально, работает с любыми полями, включая ресурсы и вычисляемые выражения. Для виртуальных таблиц — медленнее, так как фильтрация идёт после расчёта итогов

Отбор в СКД или динамическом списке

Подходит, когда условия задаёт пользователь в интерфейсе. Не заменяет условия внутри текста запроса для сложной логики

Условия по агрегатам: секция ИМЕЮЩИЕ

Секция ГДЕ не может содержать агрегатные функции (СУММА, КОЛИЧЕСТВО, МАКСИМУМ и другие), потому что она применяется до группировки. Фильтрация по итогам групп выполняется в секции ИМЕЮЩИЕ, которая идёт после СГРУППИРОВАТЬ ПО:

ВЫБРАТЬ

Продажи.Контрагент КАК Контрагент,

СУММА(Продажи.СуммаОборот) КАК СуммаПродаж

ИЗ

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

СГРУППИРОВАТЬ ПО

Продажи.Контрагент

ИМЕЮЩИЕ

СУММА(Продажи.СуммаОборот) > &МинимальнаяСумма

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

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

Конструкция ВЫБОР: условная логика внутри полей

Конструкция ВЫБОР — аналог CASE из SQL. Она позволяет вычислить значение поля по условию прямо в запросе, без постобработки в коде:

ВЫБРАТЬ

Заказы.Номер КАК Номер,

ВЫБОР

КОГДА Заказы.СуммаДокумента > 100000

ТОГДА "Крупный"

КОГДА Заказы.СуммаДокумента > 10000

ТОГДА "Средний"

ИНАЧЕ "Мелкий"

КОНЕЦ КАК Категория

ИЗ

Документ.ЗаказКлиента КАК Заказы

Ветки КОГДА проверяются сверху вниз, срабатывает первая истинная. Если ни одно условие не выполнено и ветки ИНАЧЕ нет, поле получит значение NULL — это частая причина «пустых» колонок в отчётах. Всегда добавляйте ИНАЧЕ, если NULL в результате нежелателен.

ВЫБОР можно использовать и внутри условий ГДЕ, и в агрегатных функциях. Классический приём — условная сумма: СУММА(ВЫБОР КОГДА ВидОплаты = &Наличные ТОГДА Сумма ИНАЧЕ 0 КОНЕЦ) позволяет в одной группировке получить суммы по разным категориям отдельными колонками.

Если в запросе больше двух-трёх веток ВЫБОР с одинаковыми текстовыми результатами, задумайтесь о замене на соединение с небольшой таблицей значений, помещённой во временную таблицу. Такой вариант проще поддерживать, а подписи можно менять без правки текста запроса.
ПЗ
Практическое замечание

Проверка результата и типичные ошибки

Отладку условий удобнее всего вести в консоли запросов: она показывает результат сразу и позволяет менять параметры без перезапуска кода. Порядок проверки нового запроса с условиями:

Порядок действий
  1. 1
    Напишите запрос без условий и убедитесь, что выборка в принципе содержит нужные данные
  2. 2
    Добавляйте условия по одному, после каждого проверяя количество строк в результате
  3. 3
    Проверьте граничные случаи: пустой параметр, NULL в соединении, дата на границе периода
  4. 4
    Оцените время выполнения на реальном объёме данных, а не только на тестовой базе
  5. 5
    Сравните итоговые суммы с эталонным отчётом конфигурации

Признак проблемного условия — резкое изменение числа строк при добавлении безобидного с виду фильтра. Если после И НЕ ПометкаУдаления выборка опустела полностью, проверьте, тот ли это источник и не фильтруете ли вы уже сгруппированные данные.

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

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

Количество строк в выборке
Норма

Меняется предсказуемо при добавлении каждого условия

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

Резко падает до нуля или не меняется вообще

Значения полей из левого соединения
Норма

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

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

Пустые значения сравниваются через = и строки теряются

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

Запрос с фильтром в параметрах виртуальной таблицы выполняется быстро

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

Условие в ГДЕ по виртуальной таблице даёт заметную задержку на большой базе

Частые вопросы по условиям в запросах 1С

Можно ли использовать функции встроенного языка (Найти, СтрДлина) в условиях запроса?

Нет. В тексте запроса доступны только функции языка запросов: ПОДСТРОКА, РАЗНОСТЬДАТ, НАЧАЛОПЕРИОДА, КОНЕЦПЕРИОДА, ЕСТЬNULL, ВЫРАЗИТЬ и другие. Функции встроенного языка применяются к результату запроса уже после его выполнения, при обходе выборки.

Как проверить, что строка не пустая?

Используйте сравнение с пустой строкой: ГДЕ Поле <> "". Учтите, что для строк неограниченной длины и полей с NULL это не сработает ожидаемо — добавьте проверку И НЕ Поле ЕСТЬ NULL. Для ссылок пустое значение проверяется через ЗНАЧЕНИЕ(Справочник.Имя.ПустаяСсылка).

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

Поле даты документа содержит и время. Если конец периода задан как начало последнего дня (00:00:00), все документы позже этого момента отсекаются. Передавайте конец дня (23:59:59), используйте функцию КОНЕЦПЕРИОДА(&Дата, ДЕНЬ) или стройте условие вида Дата < ДОБАВИТЬКДАТЕ(&Конец, ДЕНЬ, 1).

Что делать, если параметр-список для В() может быть пустым?

Пустой массив в В() вернёт пустую выборку, что не всегда желательно. Стандартное решение — добавить ветку: ГДЕ (&БезОтбора ИЛИ Поле В (&Список)), где БезОтбора — булев параметр, равный ИСТИНА, когда список пуст. В СКД аналогичную задачу решает настройка отбора с флагом использования.

Можно ли в ГДЕ ссылаться на поле через точку (разыменование)?

Да, например ГДЕ Документ.Контрагент.ИНН = &ИНН. Но каждое разыменование — это скрытое соединение с таблицей справочника. Одно-два разыменования допустимы, а если полей много, лучше явно соединить таблицы через ЛЕВОЕ СОЕДИНЕНИЕ — запрос станет прозрачнее и предсказуемее по производительности.

Чем отличается ВЫРАЗИТЬ в условии от обычного сравнения?

ВЫРАЗИТЬ приводит значение к указанному типу, например ВЫРАЗИТЬ(Поле КАК Справочник.Номенклатура) = &Товар. Это нужно для полей составного типа: без приведения сравнение может работать медленнее, а в некоторых сценариях СУБД не сможет использовать индекс. Приведение типа также помогает при соединении временных таблиц с полями составного типа.

Итог

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

Фильтруйте данные как можно раньше: параметры виртуальных таблиц — для регистров, ГДЕ — для обычных полей, ИМЕЮЩИЕ — для итогов группировки. NULL проверяйте только через ЕСТЬ NULL, сложную логику И/ИЛИ заключайте в скобки, а результат каждого нового условия проверяйте в консоли запросов по количеству строк.