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