Перечисления в запросах 1С: синтаксис и примеры

· 9 мин

Содержание

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

Перечисление в 1С — это фиксированный набор значений, заданный в конфигурации (статусы заказов, виды контактной информации, пол сотрудника). В реквизите хранится не строка и не число, а ссылка на элемент перечисления. Отсюда два частых вопроса: как записать такое значение прямо в запросе и как передать его параметром. Разберём оба способа, различие между Перечисление и Перечисления, отбор по нескольким значениям, типичные ошибки компиляции и приёмы оптимизации.

Функция ЗНАЧЕНИЕ(): прямое указание в тексте запроса

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

ВЫБРАТЬ
    Заказы.Номер,
    Заказы.Дата,
    Заказы.Сумма
ИЗ
    Документ.ЗаказКлиента КАК Заказы
ГДЕ
    Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Выполнен)

Разберём путь по частям:

  • Перечисление — вид объекта метаданных (в единственном числе, это важно).
  • СтатусыЗаказов — имя перечисления так, как оно задано в конфигураторе.
  • Выполнен — имя конкретного значения внутри этого перечисления.

Имена берут не из синонимов (того, что видит пользователь), а из поля «Имя» в свойствах объекта. Синоним «В работе» в конфигурации может называться ВРаботе — в запросе пишут именно ВРаботе.

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

Функцию можно использовать в любой части запроса, где допустимо значение: в ГДЕ, в ВЫБРАТЬ, в ВЫБОР КОГДА … ТОГДА, в соединениях. Например, пометить признаком строки с нужным статусом:

ВЫБРАТЬ
    Заказы.Номер,
    ВЫБОР
        КОГДА Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Отменён)
            ТОГДА "Отменён"
        ИНАЧЕ "Активен"
    КОНЕЦ КАК ПризнакСтроки
ИЗ
    Документ.ЗаказКлиента КАК Заказы

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

Здесь спотыкаются чаще всего. В запросе и во встроенном языке 1С обращение к одному и тому же значению выглядит по-разному, и перепутать легко.

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

Логика такая: внутри текста запроса Перечисление — это ветка дерева метаданных, как Документ или Справочник. А в коде на встроенном языке Перечисления — глобальное свойство-менеджер, через которое вы получаете готовое значение.

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

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

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

Второй способ нужен, когда значение определяется во время работы программы: пользователь выбрал его в форме, оно пришло из настройки или из другого объекта. Тогда в тексте запроса ставят параметр &ИмяПараметра, а значение присваивают методом УстановитьПараметр().

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ
    |    Заказы.Номер,
    |    Заказы.Сумма
    |ИЗ
    |    Документ.ЗаказКлиента КАК Заказы
    |ГДЕ
    |    Заказы.Статус = &Статус";

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

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

Когда выбирать параметр, а когда ЗНАЧЕНИЕ():

  • 🔹 Значение жёстко задано логикой и не меняется — проще ЗНАЧЕНИЕ() прямо в тексте.
  • 🔹 Значение приходит извне (из реквизита формы, настройки, цикла) — только параметр.
  • 🔹 Один и тот же запрос нужно выполнить с разными статусами — параметр: текст не меняется, подставляете разные значения.

Параметр можно заполнить и из реквизита: Запрос.УстановитьПараметр("Статус", Объект.ТекущийСтатус), если у реквизита тип ПеречислениеСсылка. Платформа сама подставит нужную ссылку.

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

Отбор по нескольким значениям и по пустой ссылке

Часто нужно оставить не один статус, а несколько. Перечислять через ИЛИ можно, но читается плохо. Чище — оператор В со списком значений:

ГДЕ
    Заказы.Статус В (
        ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Новый),
        ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.ВРаботе)
    )

Если набор статусов заранее не известен, передайте в параметр массив значений — оператор В принимает и его:

СписокСтатусов = Новый Массив;
СписокСтатусов.Добавить(Перечисления.СтатусыЗаказов.Новый);
СписокСтатусов.Добавить(Перечисления.СтатусыЗаказов.ВРаботе);

Запрос.УстановитьПараметр("Статусы", СписокСтатусов);
// в тексте:  ГДЕ Заказы.Статус В (&Статусы)

Отдельный случай — пустое значение. Реквизит типа ПеречислениеСсылка без заполнения хранит пустую ссылку. Проверить её в запросе можно так:

ГДЕ
    Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.ПустаяСсылка)

ПустаяСсылка — это не выдуманное значение, а стандартный способ получить пустую ссылку перечисления в тексте запроса. Так удобно находить документы, у которых статус вообще не задан.

Перечисления можно сравнивать операторами > и <, но порядок задаётся не алфавитом, а положением значений в конфигурации. Поэтому сравнение «больше/меньше» по перечислению надёжно только тогда, когда вы точно знаете порядок элементов и он не поменяется при доработке. В остальных случаях сравнивайте через =, <> или В.

Частые ошибки компиляции и выполнения

Большинство проблем с перечислениями всплывает при компиляции запроса — платформа сразу пишет, что путь не найден. Разберём, что за этим стоит.

Диагностика: выберите симптом

Ещё несколько ловушек, которые ошибкой не считаются, но дают неверный результат:

  • ⚠️ Отбор пустой ссылки через НЕ Статус ЕСТЬ NULL вместо сравнения с ПустаяСсылка. NULL возникает при левом соединении, когда записи нет вообще, а пустая ссылка — это заполненное, но «пустое» значение. Это разные вещи.
  • ⚠️ Сравнение >/< по перечислению после того, как в конфигурацию добавили новое значение между существующими. Порядок сместился — условие молча стало отбирать другое.
  • ⚠️ Передача в параметр значения из перечисления другого объекта. Типы ПеречислениеСсылка.СтатусыЗаказов и ПеречислениеСсылка.СтатусыОплаты несовместимы, отбор вернёт пусто.

Оптимизация отбора по перечислению

Перечисление — лёгкий тип: в базе хранится компактная ссылка, сравнение по ней быстрое. Но пару правил соблюдать стоит.

  1. Отбирайте в запросе, а не после выборки. Условие ГДЕ Заказы.Статус = ЗНАЧЕНИЕ(...) платформа выполнит на стороне СУБД. Если же выбрать все документы и фильтровать статус в цикле по результату — читаете лишние данные и теряете скорость.

  2. По одному полю-перечислению — равенство или В. Прямое сравнение оптимизатор СУБД обрабатывает хорошо. Заворачивать перечисление в ВЫБОР КОГДА … КОНЕЦ внутри ГДЕ не нужно — это мешает использовать индекс.

  3. Массив в параметре вместо длинной цепочки ИЛИ. Список значений в операторе В читается чище и, как правило, выполняется не хуже, чем набор условий через ИЛИ.

  4. Не делайте перечисление измерением регистра ради отбора, если значений два-три. Иногда признак из двух состояний логичнее хранить булевым реквизитом — отбор по булю ещё легче. Это вопрос проектирования, но он напрямую влияет на скорость запросов.

Если по статусу документов строится много отчётов и список документов большой, имеет смысл проверить, попадает ли поле статуса в индекс. Для реквизитов это настраивается свойством «Индексировать» в конфигураторе.

Проверьте себя — три коротких вопроса по синтаксису:

Проверьте себя
Какой функцией указывают значение перечисления прямо в тексте запроса?
Как в тексте запроса пишется вид объекта для перечисления?
Можно ли сравнить реквизит-перечисление со строкой "Выполнен"?

Готовые шаблоны запросов с перечислениями

Соберём разобранные приёмы в примеры, которые можно взять за основу.

Отбор документов по одному статусу — значение задано в тексте:

ВЫБРАТЬ
    Заказы.Ссылка,
    Заказы.Дата,
    Заказы.Сумма
ИЗ
    Документ.ЗаказКлиента КАК Заказы
ГДЕ
    Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.ВРаботе)
УПОРЯДОЧИТЬ ПО
    Заказы.Дата

Отбор по набору статусов — значения приходят параметром:

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ
    |    Заказы.Ссылка,
    |    Заказы.Статус
    |ИЗ
    |    Документ.ЗаказКлиента КАК Заказы
    |ГДЕ
    |    Заказы.Статус В (&Статусы)";

Статусы = Новый Массив;
Статусы.Добавить(Перечисления.СтатусыЗаказов.Новый);
Статусы.Добавить(Перечисления.СтатусыЗаказов.ВРаботе);
Запрос.УстановитьПараметр("Статусы", Статусы);

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Сообщить(Выборка.Ссылка);
КонецЦикла;

Подсчёт количества по каждому статусу — группировка по полю-перечислению:

ВЫБРАТЬ
    Заказы.Статус КАК Статус,
    КОЛИЧЕСТВО(Заказы.Ссылка) КАК Количество
ИЗ
    Документ.ЗаказКлиента КАК Заказы
СГРУППИРОВАТЬ ПО
    Заказы.Статус

Поле Статус в результате — это ссылка на перечисление. Если нужно вывести читаемый текст, в представлении таблицы или отчёта платформа сама покажет синоним значения; в коде для вывода строкой используйте Строка(Выборка.Статус).

Текстовое представление можно получить и прямо в запросе функцией ПРЕДСТАВЛЕНИЕ(). Это удобно, когда результат уходит в табличный документ или выгрузку, где нужна строка, а не ссылка:

ВЫБРАТЬ
    Заказы.Номер,
    ПРЕДСТАВЛЕНИЕ(Заказы.Статус) КАК СтатусТекст
ИЗ
    Документ.ЗаказКлиента КАК Заказы

ПРЕДСТАВЛЕНИЕ() вернёт синоним значения перечисления строкой — например, «В работе». Группировать или сравнивать по этому полю уже нельзя (это текст, а не ссылка), поэтому для отбора оставляйте ссылку, а представление берите только для вывода.

Исключить отменённые заказы и пустой статус сразу:

ГДЕ
    Заказы.Статус <> ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Отменён)
    И Заказы.Статус <> ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.ПустаяСсылка)

Эти четыре шаблона закрывают почти все задачи: точечный отбор, отбор по списку, агрегат и исключение значений. Имена перечисления и значений в них замените на свои.

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

Чем `ЗНАЧЕНИЕ()` отличается от параметра запроса?
ЗНАЧЕНИЕ() жёстко вписывает значение в текст — оно известно заранее и не меняется. Параметр &Имя подставляет значение во время выполнения, когда оно приходит из формы, настройки или цикла. Для одного и того же текста запроса параметр позволяет подставлять разные статусы.
Почему нельзя сравнить перечисление со строкой?
В реквизите хранится не текст, а ссылка типа ПеречислениеСсылка. Строка и ссылка — разные типы, платформа их не приравнивает. Поэтому значение задают только через ЗНАЧЕНИЕ() или параметр со ссылкой.
Как в запросе проверить, что значение перечисления не заполнено?
Сравните поле с пустой ссылкой: Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.ПустаяСсылка). Это не то же самое, что ЕСТЬ NULL — NULL появляется при соединениях, когда записи нет совсем, а пустая ссылка означает заполненный, но «пустой» реквизит.
Как передать в запрос сразу несколько значений перечисления?
Используйте оператор В со списком ЗНАЧЕНИЕ(...) прямо в тексте либо передайте в параметр массив значений (Перечисления.Имя.Значение) и напишите В (&Параметр).
Почему запрос пишет «Поле не обнаружено Перечисление…»?
Имя перечисления или значения указано неверно: опечатка, либо взят синоним вместо имени из конфигуратора, либо написано Перечисления во множественном числе внутри ЗНАЧЕНИЕ(). Сверьте путь буква в букву со свойством «Имя» объекта.