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