Разработка и Конфигурация · 9 мин
Как в запросе 1С сравнить с перечислением
Как сравнить значение с перечислением в запросе 1С: ЗНАЧЕНИЕ(), параметры, ССЫЛКА, В ИЕРАРХИИ. Примеры кода, типичные ошибки и ответы на вопросы.
Сравнение поля запроса со значением перечисления — одна из самых частых задач при написании запросов в 1С. Перечисления хранятся в базе как ссылочные значения, поэтому сравнивать их нельзя со строкой или числом: нужен специальный синтаксис. Язык запросов предоставляет для этого оператор ЗНАЧЕНИЕ(), а также возможность передать значение через параметр.
Ошибка в таком сравнении проявляется двумя способами: либо запрос падает с ошибкой «Неверные параметры в операции сравнения», либо молча возвращает пустой результат. Обе ситуации разбираются ниже с конкретными примерами кода.
Материал применим к управляемым и обычным формам, к консоли запросов, схемам компоновки данных и программному выполнению запросов через объект Запрос.
Основной способ: оператор ЗНАЧЕНИЕ()
Оператор ЗНАЧЕНИЕ() позволяет получить ссылку на конкретное значение перечисления прямо в тексте запроса, без предварительной передачи параметров. Синтаксис строится по шаблону: ЗНАЧЕНИЕ(Перечисление.ИмяПеречисления.ИмяЗначения).
Пример запроса, который выбирает контрагентов с определённым видом из перечисления «ВидыКонтрагентов»:
ВЫБРАТЬ
Контрагенты.Ссылка,
Контрагенты.Наименование
ИЗ
Справочник.Контрагенты КАК Контрагенты
ГДЕ
Контрагенты.ВидКонтрагента = ЗНАЧЕНИЕ(Перечисление.ВидыКонтрагентов.Поставщик)
Имя перечисления и имя значения указываются так, как они заданы в конфигураторе, — не синонимы, а именно имена метаданных. Если значение переименуют в конфигурации, запрос перестанет работать, поэтому такая жёсткая привязка — одновременно и слабое место способа.
Сравнение через параметр запроса
Когда значение перечисления определяется в коде динамически — например, выбрано пользователем на форме — удобнее передать его параметром. В тексте запроса параметр обозначается символом &:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Документы.Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Документы
|ГДЕ
| Документы.Статус = &Статус";
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыДокументов.Проведен);
Значение параметра должно быть именно ссылкой на перечисление, полученной через Перечисления.ИмяПеречисления.ИмяЗначения или вычитанной из реквизита объекта. Если передать строку «Проведен» — сравнение не сработает, потому что типы различаются.
Параметризованный вариант предпочтительнее в универсальном коде: запрос не нужно переписывать при переименовании значений, а один и тот же текст используется для разных значений перечисления.
Сравнение вариантов
Подходит для фиксированных условий в отчётах и СКД. Ограничение: ломается при переименовании значения в конфигураторе.
Подходит для динамических условий и переиспользуемого кода. Требует установки параметра в коде перед выполнением.
Подходит для проверки на несколько значений перечисления сразу. Параметр должен быть массивом или списком значений.
Сравнение с несколькими значениями и пустым значением
Для проверки поля на вхождение в несколько значений перечисления используется оператор В со списком:
ГДЕ
Товары.СтавкаНДС В (ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.НДС20),
ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.НДС10))
Альтернатива — передать массив значений в параметр и написать ГДЕ Товары.СтавкаНДС В (&СписокСтавок). В коде параметр заполняется массивом:
МассивСтавок = Новый Массив;
МассивСтавок.Добавить(Перечисления.СтавкиНДС.НДС20);
МассивСтавок.Добавить(Перечисления.СтавкиНДС.НДС10);
Запрос.УстановитьПараметр("СписокСтавок", МассивСтавок);
Отдельный случай — проверка на незаполненное значение. Для перечисления пустая ссылка получается через ЗНАЧЕНИЕ(Перечисление.ИмяПеречисления.ПустаяСсылка). Сравнение с NULL здесь не подходит: пустая ссылка и NULL в 1С — разные сущности.
Проверка типа поля и составные типы
Если реквизит имеет составной тип (например, может хранить и перечисление, и ссылку на справочник), простое сравнение со значением перечисления отсекает записи другого типа автоматически. Но иногда нужно явно проверить, что поле хранит именно перечисление. Для этого служит оператор ССЫЛКА:
ГДЕ
Регистр.ВидОперации ССЫЛКА Перечисление.ВидыОпераций
Обратная задача — выбрать записи, где поле НЕ является значением перечисления, — решается отрицанием: ГДЕ НЕ Поле ССЫЛКА Перечисление.ИмяПеречисления. Такая проверка полезна при анализе данных после конвертации, когда в реквизите могли остаться значения неожиданных типов.
Для виртуальных таблиц регистров условие по перечислению следует помещать в параметры виртуальной таблицы (в фигурных скобках конструктора запроса), а не в секцию ГДЕ. Это существенно ускоряет выполнение, так как отбор применяется до соединения таблиц.
Проверка результата и альтернативы
Чтобы убедиться, что сравнение работает, выполните запрос в консоли запросов дважды: с условием и без него. Если без условия записи есть, а с условием их нет — проблема в типе сравниваемого значения или в том, что в данных реально нет такого значения. Быстрая проверка содержимого: выведите поле в выборку и посмотрите его значения и тип через функцию ТипЗнч() в коде.
В схеме компоновки данных значения перечислений в отборах подставляются автоматически: пользователь выбирает значение из списка, и СКД сама формирует корректное сравнение. Поэтому для отчётов часто не нужно писать ЗНАЧЕНИЕ() вручную — достаточно вынести поле в отбор.
Что важно запомнить
Перечисление в запросе сравнивается через ЗНАЧЕНИЕ(Перечисление.Имя.Значение) или параметр со ссылкой на перечисление. Пустое значение проверяется через ПустаяСсылка, а не NULL. Строки и числа для сравнения не подходят.
Частые вопросы
Как сравнить с перечислением, если его значение выбирает пользователь на форме?
Передайте выбранное значение в запрос параметром: Запрос.УстановитьПараметр("Значение", ВыбранноеЗначение), а в тексте используйте условие ГДЕ Поле = &Значение. Значение с формы уже будет ссылкой на перечисление, дополнительные преобразования не нужны.
Почему запрос с ЗНАЧЕНИЕ() возвращает пустой результат?
Чаще всего причины две: в данных действительно нет записей с этим значением, либо поле имеет составной тип и хранит значения другого типа. Проверьте выборку без условия и посмотрите, какие значения фактически содержит поле.
Можно ли сравнить перечисление по его представлению (синониму)?
Нет, в языке запросов сравнение идёт по ссылке, а не по тексту представления. Если нужен отбор по тексту, придётся получать представление через соединение и сравнивать строки, но это неэффективно. Правильный путь — ссылка через ЗНАЧЕНИЕ() или параметр.
Как проверить, что поле не заполнено, если его тип — перечисление?
Используйте условие ГДЕ Поле = ЗНАЧЕНИЕ(Перечисление.ИмяПеречисления.ПустаяСсылка). Проверка ЕСТЬ NULL здесь не подходит: NULL возникает при соединениях таблиц, а незаполненный реквизит хранит именно пустую ссылку.
Работает ли ЗНАЧЕНИЕ() в запросах к внешним источникам данных?
В запросах к внешним источникам данных оператор ЗНАЧЕНИЕ() для перечислений конфигурации может быть недоступен или работать с ограничениями — это зависит от типа источника. В таких случаях надёжнее передавать значение параметром.
Что быстрее: ЗНАЧЕНИЕ() в тексте или параметр?
С точки зрения скорости выполнения разницы практически нет — оба варианта подставляют ссылку в условие. Выбор определяется удобством сопровождения: параметр гибче, ЗНАЧЕНИЕ() нагляднее для фиксированных условий.