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

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

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

Как правильно написать условие в запросе 1С: оператор ГДЕ, сравнение, В, ИЕРАРХИЯ, ССЫЛКА, ВЫРАЗИТЬ, параметры и типичные ошибки с примерами кода.

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

Язык запросов 1С похож на SQL, но имеет свои особенности: параметры начинаются со знака «&», есть специальные операторы для иерархии и проверки типов, а значения перечислений и предопределённых элементов задаются через функцию ЗНАЧЕНИЕ. Ниже разобраны основные приёмы написания условий с готовыми примерами кода.

Базовый синтаксис оператора ГДЕ

Условие записывается после секции ИЗ (или после секции соединений, если таблиц несколько) и начинается с ключевого слова ГДЕ. В простейшем виде это сравнение поля со значением:

ВЫБРАТЬ

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

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

ИЗ

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

ГДЕ

Номенклатура.Артикул = "Б-000123"

Несколько условий объединяются логическими операторами И, ИЛИ и НЕ. Оператор И имеет приоритет над ИЛИ, поэтому при смешанных условиях всегда ставьте скобки — это исключает неочевидное поведение:

ГДЕ

Товары.Склад = &Склад

И (Товары.Количество > 0 ИЛИ Товары.Резерв > 0)

Для сравнения доступны стандартные операторы: =, <> (не равно), >, <, >=, <=. Сравнение дат, чисел и строк работает напрямую, но важно, чтобы типы сравниваемых значений совпадали — об этом подробнее в разделе про типы.

Условия с параметрами и оператором В

Жёстко зашивать значения в текст запроса — плохая практика: при изменении условия придётся править код, а при конкатенации строк возникает риск ошибок и некорректных запросов. Правильный способ — параметры, которые начинаются со знака «&» и заполняются через метод УстановитьПараметр:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Заказы.Ссылка

|ИЗ

| Документ.ЗаказПокупателя КАК Заказы

|ГДЕ

| Заказы.Дата МЕЖДУ &НачалоПериода И &КонецПериода

| И Заказы.Контрагент = &Контрагент";

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

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

Запрос.УстановитьПараметр("Контрагент", ВыбранныйКонтрагент);

Если нужно отобрать по списку значений, используйте оператор В. В параметр можно передать массив или список значений — платформа сама развернёт его в набор условий:

ГДЕ

Номенклатура.ВидНоменклатуры В (&СписокВидов)

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

Оператор МЕЖДУ включает граничные значения, поэтому для дат передавайте конец дня (или используйте сравнение Дата < &КонецПериода со следующим днём), иначе документы за последний день могут частично потеряться, если в дате хранится время.

Условия для ссылок, перечислений и иерархии

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

ГДЕ

Реализация.Валюта = ЗНАЧЕНИЕ(Справочник.Валюты.Рубль)

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

Для отбора по группе справочника вместе со всеми вложенными группами используется оператор В ИЕРАРХИИ. Без него условие «Родитель = &Группа» отберёт только элементы первого уровня:

ГДЕ

Номенклатура.Ссылка В ИЕРАРХИИ (&ГруппаТоваров)

Проверить, что поле с составного типа содержит ссылку конкретного вида, можно оператором ССЫЛКА. Это полезно, например, для регистров с составным измерением:

ГДЕ

Взаиморасчеты.ДокументРасчетов ССЫЛКА Документ.ЗаказПокупателя

Сравнение вариантов отбора по группе

Родитель = &Группа

Отбирает только элементы, лежащие непосредственно в указанной группе. Вложенные подгруппы не попадут в результат.

Ссылка В ИЕРАРХИИ (&Группа)

Отбирает элементы группы и всех вложенных уровней. Работает медленнее, но даёт полный охват.

Ссылка = &Группа

Отберёт только саму группу как элемент, почти никогда не то, что нужно на практике.

Работа со строками, NULL и составными типами

Для поиска по части строки применяется оператор ПОДОБНО с шаблоном: символ «%» заменяет любую последовательность символов, «_» — один символ. Учтите, что поиск с ведущим «%» не использует индекс и на больших таблицах работает медленно:

ГДЕ

Контрагенты.Наименование ПОДОБНО "%" + &Фрагмент + "%"

Значение NULL появляется при левых соединениях и в необязательных реквизитах. Сравнение «Поле = NULL» всегда ложно, поэтому проверка пишется так:

ГДЕ

Товары.Характеристика ЕСТЬ NULL

Если поле имеет составной тип (например, строка или ссылка), сравнение с параметром другого типа вернёт ложь без ошибки. Чтобы условие работало предсказуемо, приведите тип функцией ВЫРАЗИТЬ:

ГДЕ

ВЫРАЗИТЬ(Комментарии.Объект КАК Документ.ЗаказПокупателя) = &Заказ

Типичные ошибки в условиях
01
Сравнение NULL через равенство — условие молча не срабатывает, строки теряются; используйте ЕСТЬ NULL.
02
Отбор по группе через Родитель = &Группа — вложенные подгруппы не попадают в выборку; нужен В ИЕРАРХИИ.
03
Сравнение составного поля с параметром без ВЫРАЗИТЬ — типы не совпадают, результат пустой.
04
Конец периода без КонецДня — документы последнего дня с временем позже 00:00:00 выпадают из выборки.
05
Условия по полям виртуальной таблицы в ГДЕ вместо её параметров — СУБД сначала строит всю таблицу, запрос резко замедляется.

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

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

ВЫБРАТЬ

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

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

ИЗ

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

&ДатаОстатков,

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

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

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

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

Проверка условия в консоли запросов

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

Порядок отладки условия
  1. 1
    Откройте консоль запросов или конструктор запроса и вставьте текст запроса.
  2. 2
    Заполните все параметры реальными значениями из базы — не тестовыми строками.
  3. 3
    Выполните запрос и сверьте количество строк с ожидаемым: заведомо известной карточкой или документом.
  4. 4
    Уберите условия по одному, чтобы найти то, которое отсекает нужные данные.
  5. 5
    Проверьте пограничные случаи: NULL в полях, дату с временем, элемент вложенной группы.
  6. 6
    Только после этого переносите текст в модуль и подставляйте параметры программно.

Признак корректного условия — запрос возвращает ровно те строки, которые вы можете найти в базе вручную через списки справочников и документов. Если строк меньше, чем ожидалось, чаще всего виноваты NULL, несовпадение типов или дата с временем.

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

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

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

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

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

Строк меньше — проверяйте NULL, типы и границы дат

Элемент из вложенной подгруппы
Норма

Попадает в выборку при В ИЕРАРХИИ

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

Отсутствует — в условии используется Родитель =

Документы последнего дня периода
Норма

Все документы дня присутствуют

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

Часть документов с временем отсутствует — нет КонецДня

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

Отбор задан параметрами виртуальной таблицы

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

Условия по измерениям стоят в ГДЕ, запрос тормозит

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

Чем отличается ГДЕ от ИМЕЮЩИЕ?

ГДЕ фильтрует строки до группировки, а ИМЕЮЩИЕ — уже сгруппированные итоги. Если нужно отобрать группы, где сумма больше заданной, условие пишется в ИМЕЮЩИЕ: СУММА(Продажи.Сумма) > &Порог. Условия по отдельным полям без агрегатов эффективнее оставлять в ГДЕ.

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

Используйте конструкцию с ИЛИ: ГДЕ (&Параметр = НЕОПРЕДЕЛЕНО ИЛИ Поле = &Параметр). Тогда при незаполненном параметре отбор не применяется, а при заполненном — работает. Для ссылок вместо НЕОПРЕДЕЛЕНО можно сравнивать с пустой ссылкой через ЗНАЧЕНИЕ(Справочник.Имя.ПустаяСсылка).

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

Дата документа хранится со временем. Если в параметр конца периода передать дату без времени, она превратится в 00:00:00, и все документы позже полуночи выпадут. Передавайте КонецДня(Дата) в параметр или используйте условие Дата < &СледующийДень.

Можно ли использовать функцию в условии запроса?

Да, доступны встроенные функции языка запросов: НАЧАЛОПЕРИОДА, КОНЕЦПЕРИОДА, ДОБАВИТЬКДАТЕ, РАЗНОСТЬДАТ, ПОДСТРОКА и другие. Например: ГДЕ НАЧАЛОПЕРИОДА(Заказ.Дата, ДЕНЬ) = &День. Произвольные функции общих модулей в запросе вызывать нельзя.

Как отобрать записи, где ссылка битая?

Прямого оператора проверки битой ссылки в языке запросов нет. Практический приём — левое соединение с таблицей соответствующего объекта и проверка, что присоединённая ссылка ЕСТЬ NULL: если ссылка есть, а объекта в таблице нет, значит ссылка битая.

Что быстрее: несколько условий через ИЛИ или оператор В?

Оператор В со списком значений читается проще и обычно не уступает цепочке ИЛИ по скорости. Кроме того, В позволяет передать список одним параметром, что удобно, когда набор значений формируется программно и заранее неизвестен.

Итог

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

Условия пишутся после ГДЕ с параметрами вида &Имя; NULL проверяется через ЕСТЬ NULL, иерархия — через В ИЕРАРХИИ, тип ссылки — через ССЫЛКА и ВЫРАЗИТЬ. Отборы по измерениям виртуальных таблиц задавайте в их параметрах, а текст запроса всегда проверяйте в консоли до переноса в код.