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