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

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

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

Как сравнить значение с перечислением в запросе 1С: ЗНАЧЕНИЕ(), параметры, ССЫЛКА, В ИЕРАРХИИ. Примеры кода, типичные ошибки и ответы на вопросы.

Сравнение поля запроса со значением перечисления — одна из самых частых задач при написании запросов в 1С. Перечисления хранятся в базе как ссылочные значения, поэтому сравнивать их нельзя со строкой или числом: нужен специальный синтаксис. Язык запросов предоставляет для этого оператор ЗНАЧЕНИЕ(), а также возможность передать значение через параметр.

Ошибка в таком сравнении проявляется двумя способами: либо запрос падает с ошибкой «Неверные параметры в операции сравнения», либо молча возвращает пустой результат. Обе ситуации разбираются ниже с конкретными примерами кода.

Материал применим к управляемым и обычным формам, к консоли запросов, схемам компоновки данных и программному выполнению запросов через объект Запрос.

Основной способ: оператор ЗНАЧЕНИЕ()

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

Пример запроса, который выбирает контрагентов с определённым видом из перечисления «ВидыКонтрагентов»:

ВЫБРАТЬ

Контрагенты.Ссылка,

Контрагенты.Наименование

ИЗ

Справочник.Контрагенты КАК Контрагенты

ГДЕ

Контрагенты.ВидКонтрагента = ЗНАЧЕНИЕ(Перечисление.ВидыКонтрагентов.Поставщик)

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

Сравнение через параметр запроса

Когда значение перечисления определяется в коде динамически — например, выбрано пользователем на форме — удобнее передать его параметром. В тексте запроса параметр обозначается символом &:

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

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

"ВЫБРАТЬ

| Документы.Ссылка

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Документы

|ГДЕ

| Документы.Статус = &Статус";

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

Значение параметра должно быть именно ссылкой на перечисление, полученной через Перечисления.ИмяПеречисления.ИмяЗначения или вычитанной из реквизита объекта. Если передать строку «Проведен» — сравнение не сработает, потому что типы различаются.

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

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

ЗНАЧЕНИЕ() в тексте запроса

Подходит для фиксированных условий в отчётах и СКД. Ограничение: ломается при переименовании значения в конфигураторе.

Параметр запроса

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

Список значений через В (...)

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

Сравнение с несколькими значениями и пустым значением

Для проверки поля на вхождение в несколько значений перечисления используется оператор В со списком:

ГДЕ

Товары.СтавкаНДС В (ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.НДС20),

ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.НДС10))

Альтернатива — передать массив значений в параметр и написать ГДЕ Товары.СтавкаНДС В (&СписокСтавок). В коде параметр заполняется массивом:

МассивСтавок = Новый Массив;

МассивСтавок.Добавить(Перечисления.СтавкиНДС.НДС20);

МассивСтавок.Добавить(Перечисления.СтавкиНДС.НДС10);

Запрос.УстановитьПараметр("СписокСтавок", МассивСтавок);

Отдельный случай — проверка на незаполненное значение. Для перечисления пустая ссылка получается через ЗНАЧЕНИЕ(Перечисление.ИмяПеречисления.ПустаяСсылка). Сравнение с NULL здесь не подходит: пустая ссылка и NULL в 1С — разные сущности.

Проверка типа поля и составные типы

Если реквизит имеет составной тип (например, может хранить и перечисление, и ссылку на справочник), простое сравнение со значением перечисления отсекает записи другого типа автоматически. Но иногда нужно явно проверить, что поле хранит именно перечисление. Для этого служит оператор ССЫЛКА:

ГДЕ

Регистр.ВидОперации ССЫЛКА Перечисление.ВидыОпераций

Обратная задача — выбрать записи, где поле НЕ является значением перечисления, — решается отрицанием: ГДЕ НЕ Поле ССЫЛКА Перечисление.ИмяПеречисления. Такая проверка полезна при анализе данных после конвертации, когда в реквизите могли остаться значения неожиданных типов.

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

Проверка результата и альтернативы

Чтобы убедиться, что сравнение работает, выполните запрос в консоли запросов дважды: с условием и без него. Если без условия записи есть, а с условием их нет — проблема в типе сравниваемого значения или в том, что в данных реально нет такого значения. Быстрая проверка содержимого: выведите поле в выборку и посмотрите его значения и тип через функцию ТипЗнч() в коде.

В схеме компоновки данных значения перечислений в отборах подставляются автоматически: пользователь выбирает значение из списка, и СКД сама формирует корректное сравнение. Поэтому для отчётов часто не нужно писать ЗНАЧЕНИЕ() вручную — достаточно вынести поле в отбор.

Итог

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

Перечисление в запросе сравнивается через ЗНАЧЕНИЕ(Перечисление.Имя.Значение) или параметр со ссылкой на перечисление. Пустое значение проверяется через ПустаяСсылка, а не NULL. Строки и числа для сравнения не подходят.

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

Как сравнить с перечислением, если его значение выбирает пользователь на форме?

Передайте выбранное значение в запрос параметром: Запрос.УстановитьПараметр("Значение", ВыбранноеЗначение), а в тексте используйте условие ГДЕ Поле = &Значение. Значение с формы уже будет ссылкой на перечисление, дополнительные преобразования не нужны.

Почему запрос с ЗНАЧЕНИЕ() возвращает пустой результат?

Чаще всего причины две: в данных действительно нет записей с этим значением, либо поле имеет составной тип и хранит значения другого типа. Проверьте выборку без условия и посмотрите, какие значения фактически содержит поле.

Можно ли сравнить перечисление по его представлению (синониму)?

Нет, в языке запросов сравнение идёт по ссылке, а не по тексту представления. Если нужен отбор по тексту, придётся получать представление через соединение и сравнивать строки, но это неэффективно. Правильный путь — ссылка через ЗНАЧЕНИЕ() или параметр.

Как проверить, что поле не заполнено, если его тип — перечисление?

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

Работает ли ЗНАЧЕНИЕ() в запросах к внешним источникам данных?

В запросах к внешним источникам данных оператор ЗНАЧЕНИЕ() для перечислений конфигурации может быть недоступен или работать с ограничениями — это зависит от типа источника. В таких случаях надёжнее передавать значение параметром.

Что быстрее: ЗНАЧЕНИЕ() в тексте или параметр?

С точки зрения скорости выполнения разницы практически нет — оба варианта подставляют ссылку в условие. Выбор определяется удобством сопровождения: параметр гибче, ЗНАЧЕНИЕ() нагляднее для фиксированных условий.