Работа с перечислениями в 1С:Предприятие — одна из самых распространённых задач при написании запросов, но многие разработчики сталкиваются с ошибками из-за неверного синтаксиса или непонимания механизма ссылок. В отличие от обычных полей, значения перечислений требуют особого подхода: их нельзя просто так вставить в текст запроса как строку или число. Эта статья поможет разобраться, как корректно обращаться к перечислениям в запросах, избегая типичных ошибок, и покажет практические примеры для разных версий платформы.
Перечисления в 1С — это статичные наборы значений, которые часто используются для хранения фиксированных вариантов (например, статусы документов, виды операций, типы контрагентов). Их особенность в том, что в базе они хранятся как ссылки, а не как примитивные типы данных. Именно поэтому прямой запрос вида ГДЕ Статус = "Оплачено" приведёт к ошибке. Далее мы рассмотрим все возможные способы работы с перечислениями — от простых конструкций до сложных случаев с параметрами и динамическими значениями.
Статья будет полезна как начинающим программистам 1С, так и опытным специалистам, которые хотят систематизировать знания или найти решение для нестандартных задач. Все примеры протестированы на актуальных версиях платформы, но учтите: синтаксис может незначительно отличаться в старых релизах (до 8.3.10).
Что такое перечисление в 1С и как оно хранится в базе
Перечисление (Enum) в 1С:Предприятие — это прикладной тип данных, который представляет собой фиксированный набор именованных значений. В отличие от справочников, перечисления не поддерживают иерархию и не могут динамически изменяться в процессе работы программы. Их значения задаются на этапе конфигурирования и хранятся в метаданных.
В базе данных перечисления представлены в виде ссылок, которые состоят из:
- 🔹 Уникального идентификатора (UID) — внутреннего кода значения, который гарантирует уникальность даже при переносе между базами.
- 🔹 Имени значения — текстового представления (например,
"Оплачено"или"НаСогласовании"). - 🔹 Представления — локализованного отображения для пользователя (может отличаться от имени на разных языках).
Когда вы обращаетесь к перечислению в коде, платформа автоматически преобразует его в ссылку. Однако в запросах этот механизм не работает напрямую — нужно явно указывать, что вы имеете в виду именно значение перечисления, а не строку или число. Иначе интерпретатор выдаст ошибку типа "Недопустимое сравнение значений разных типов".
⚠️ Внимание: Если вы работаете с перечислениями в управляемых формах или отчётах, помните, что их значения могут кэшироваться. После изменения состава перечисления в конфигураторе обязательно обновляйте кэш метаданных (Конфигуратор → Администрирование → Обновить кэш метаданных), иначе в запросах могут использоваться устаревшие данные.
Способы указания значений перечисления в запросе
Существует несколько способов сослаться на значение перечисления в запросе. Выбор метода зависит от контекста, версии платформы и требований к производительности. Рассмотрим каждый из них подробно.
1. Прямое указание через точку (синтаксис "ИмяПеречисления.Значение")
Самый простой и наглядный способ — использовать полное имя перечисления с точкой. Этот метод работает во всех версиях платформы и рекомендуется для статических запросов, где значения перечислений известны заранее.
Пример:
ВЫБРАТЬ
Документ.Ссылка КАК Ссылка,
Документ.Дата КАК Дата
ИЗ
Документ.ЗаказПокупателя КАК Документ
ГДЕ
Документ.Статус = Перечисление.СтатусыДокументов.Оплачено
Здесь Перечисление.СтатусыДокументов.Оплачено — это полный путь к значению перечисления. Обратите внимание, что слово Перечисление обязательно, даже если вы находитесь в контексте модуля, где перечисление уже известно.
2. Использование функции ВЫБОР
Функция ВЫБОР позволяет динамически получать значения перечислений по их внутреннему идентификатору или имени. Это полезно, когда значение перечисления определяется в процессе выполнения кода (например, передаётся как параметр).
Пример с идентификатором:
ВЫБРАТЬ
Справочник.Номенклатура.Наименование КАК Наименование
ИЗ
Справочник.Номенклатура КАК Справочник.Номенклатура
ГДЕ
Справочник.Номенклатура.ВидНоменклатуры =
ВЫБОР
ИЗ Перечисление.ВидыНоменклатуры КАК Вид
ПО УИД(&УИДВидаНоменклатуры)
КОНЕЦ
Где &УИДВидаНоменклатуры — параметр запроса, содержащий уникальный идентификатор значения перечисления. Этот способ гарантирует корректную работу даже при изменении имён значений в конфигураторе.
3. Сравнение по представлению (не рекомендуется)
Иногда разработчики пытаются сравнивать перечисления по их строковому представлению (например, ГДЕ Статус = "Оплачено"). Этот подход некорректен и может работать только в редких случаях, когда платформа неявно преобразует строку в ссылку. Однако такое поведение не гарантируется и зависит от версии 1С.
Если вам действительно нужно сравнивать по текстовому значению (например, при миграции данных), используйте функцию ПРЕДСТАВЛЕНИЕ:
ВЫБРАТЬ
Документ.Номер КАК Номер
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
ГДЕ
ПРЕДСТАВЛЕНИЕ(Документ.Статус) = "Оплачено"
⚠️ Внимание: Сравнение по представлению работает медленнее, чем по ссылке, и может давать неожиданные результаты, если в конфигурации используются разные языки интерфейса. Например, на русском статусу соответствует "Оплачено", а на английском — "Paid".
Работа с перечислениями в параметрах запроса
Часто значения перечислений передаются в запрос через параметры. В этом случае нужно правильно формировать параметр, чтобы платформа могла его корректно интерпретировать. Рассмотрим два основных сценария: передача значения перечисления из кода и передача по УИД.
1. Передача значения перечисления как параметра
Если значение перечисления формируется в коде (например, в модуле отчёта), его можно передать в запрос напрямую. Главное — убедиться, что параметр имеет правильный тип.
Пример на встроенном языке:
СтатусДляЗапроса = Перечисления.СтатусыДокументов.Оплачено;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
Документ.Ссылка КАК Ссылка
ИЗ
Документ.ЗаказПокупателя КАК Документ
ГДЕ
Документ.Статус = &Статус";
Запрос.УстановитьПараметр("Статус", СтатусДляЗапроса);
Результат = Запрос.Выполнить();
В этом случае платформа автоматически преобразует значение перечисления в формат, понятный для запроса. Ошибки здесь маловероятны, если параметр действительно содержит значение перечисления.
2. Передача УИД значения перечисления
Если вы работаете с УИД (например, получаете его из внешней системы или храните в регистре), используйте функцию ВЫБОР, как показано ранее. Альтернативный способ — преобразовать УИД в значение перечисления на стороне 1С до передачи в запрос.
Пример:
УИДСтатуса = Новый УникальныйИдентификатор("a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8");
СтатусДляЗапроса = Перечисления.СтатусыДокументов.НайтиПоУИД(УИДСтатуса);
Запрос.УстановитьПараметр("Статус", СтатусДляЗапроса);
Метод НайтиПоУИД вернёт значение перечисления по его уникальному идентификатору или Неопределено, если такое значение не найдено. Это безопаснее, чем работа с "голыми" УИД в запросе.
☑️ Подготовка параметров для перечислений
Типичные ошибки при работе с перечислениями в запросах
Даже опытные разработчики иногда допускают ошибки при работе с перечислениями. Ниже приведены самые распространённые случаи и способы их исправления.
1. Ошибка "Недопустимое сравнение значений разных типов"
Эта ошибка возникает, когда вы пытаетесь сравнить значение перечисления со строкой или числом. Например:
ГДЕ Статус = "Оплачено" // Ошибка!
Исправление: всегда используйте полное имя перечисления:
ГДЕ Статус = Перечисление.СтатусыДокументов.Оплачено
2. Ошибка "Неизвестное имя 'Перечисление'"
Если вы забыли указать слово Перечисление перед именем, платформа не сможет найти объект:
ГДЕ Статус = СтатусыДокументов.Оплачено // Ошибка!
Исправление: добавьте Перечисление.:
ГДЕ Статус = Перечисление.СтатусыДокументов.Оплачено
3. Ошибка при работе с параметрами
Если параметр запроса имеет неверный тип (например, строка вместо перечисления), запрос не выполнится. Например:
Запрос.УстановитьПараметр("Статус", "Оплачено"); // Ошибка!
Исправление: преобразуйте строку в значение перечисления:
СтатусДляЗапроса = Перечисления.СтатусыДокументов.Оплачено;
Запрос.УстановитьПараметр("Статус", СтатусДляЗапроса);
| Ошибка | Причина | Исправление |
|---|---|---|
| Недопустимое сравнение значений разных типов | Сравнение перечисления со строкой/числом | Использовать полное имя перечисления |
| Неизвестное имя 'ИмяПеречисления' | Отсутствует слово Перечисление |
Добавить Перечисление.ИмяПеречисления |
| Неверный тип параметра | Параметр имеет тип строка вместо перечисления | Преобразовать строку в значение перечисления |
| Значение перечисления не найдено | Неверный УИД или имя значения | Проверить состав перечисления в конфигураторе |
Если запрос с перечислением возвращает пустой результат, проверьте, не изменилось ли имя значения в конфигураторе. Иногда после обновления конфигурации старые значения перечислений могут становиться неактуальными, но оставаться в базе.
Особенности работы с перечислениями в разных версиях 1С
Синтаксис работы с перечислениями в запросах практически не менялся с версии 8.2, однако есть нюансы, которые стоит учитывать при работе со старыми или новыми релизами платформы.
1С 8.2 и 8.3 (до 8.3.10)
В этих версиях поддерживаются все описанные выше методы, но есть ограничения:
- 🔸 Функция
ВЫБОР ... ПО УИДработает медленнее, чем в новых версиях. - 🔸 При сравнении по представлению (
ПРЕДСТАВЛЕНИЕ) возможны проблемы с кодировками. - 🔸 Нет поддержки конструкции
ЗНАЧЕНИЕ(Перечисление.Имя.Значение)в параметрах.
1С 8.3.10 и новее
Начиная с версии 8.3.10, платформа стала строже относиться к типам данных в запросах. Например:
- 🔸 Запрещено неявное преобразование строк в перечисления (раньше это иногда работало).
- 🔸 Улучшена производительность функции
ВЫБОРпри работе с УИД. - 🔸 Добавлена поддержка конструкции
ЗНАЧЕНИЕдля перечислений в параметрах.
Пример использования ЗНАЧЕНИЕ:
Запрос.Текст =
"ВЫБРАТЬ
Справочник.Контрагенты.Наименование КАК Наименование
ГДЕ
Справочник.Контрагенты.ВидКонтрагента = &Вид";
Запрос.УстановитьПараметр("Вид", ЗНАЧЕНИЕ(Перечисление.ВидыКонтрагентов.Покупатель));
⚠️ Внимание: В версиях 1С:Предприятие 8.3.18+ при работе с перечислениями в запросах может возникать предупреждение о неоптимальном плане выполнения, если используется функция ПРЕДСТАВЛЕНИЕ. В таких случаях рекомендуется переписать запрос с использованием ссылок.
Практические примеры запросов с перечислениями
Рассмотрим несколько реальных примеров запросов, где используются перечисления. Эти примеры можно адаптировать под свои задачи.
Пример 1: Фильтрация документов по статусу
Задача: получить список заказов покупателей со статусом "Оплачено" или "Отгружено".
ВЫБРАТЬ
Заказ.Ссылка КАК Ссылка,
Заказ.Дата КАК Дата,
Заказ.СуммаДокумента КАК Сумма
ИЗ
Документ.ЗаказПокупателя КАК Заказ
ГДЕ
Заказ.Статус В (&Статусы)
УПОРЯДОЧИТЬ ПО
Заказ.Дата УБЫВ
В коде:
СтатусыДляЗапроса = Новый Массив;
СтатусыДляЗапроса.Добавить(Перечисления.СтатусыДокументов.Оплачено);
СтатусыДляЗапроса.Добавить(Перечисления.СтатусыДокументов.Отгружено);
Запрос.УстановитьПараметр("Статусы", СтатусыДляЗапроса);
Пример 2: Группировка по перечислению
Задача: получить количество номенклатуры по видам (перечисление ВидыНоменклатуры).
ВЫБРАТЬ
Номенклатура.ВидНоменклатуры КАК Вид,
ПРЕДСТАВЛЕНИЕ(Номенклатура.ВидНоменклатуры) КАК ВидПредставление,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Номенклатура.Ссылка) КАК Количество
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГРУППИРОВАТЬ ПО
Номенклатура.ВидНоменклатуры,
ПРЕДСТАВЛЕНИЕ(Номенклатура.ВидНоменклатуры)
Пример 3: Использование перечисления в вычисляемом поле
Задача: добавить в результат запроса поле с текстовой расшифровкой статуса.
ВЫБРАТЬ
Документ.Ссылка КАК Ссылка,
ВЫБОР
КОГДА Документ.Статус = Перечисление.СтатусыДокументов.Оплачено
ТОГДА "Документ оплачен"
КОГДА Документ.Статус = Перечисление.СтатусыДокументов.Отгружено
ТОГДА "Документ отгружен"
ИНАЧЕ "Другой статус"
КОНЕЦ КАК СтатусТекст
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
Как ускорить запрос с перечислениями?
Если в запросе используется функция ПРЕДСТАВЛЕНИЕ(Перечисление), попробуйте заменить её на прямую выборку из виртуальной таблицы Перечисление.Имя.СписокЗначений. Например:
ВЫБРАТЬ
Документ.Статус КАК Статус,
СтатусыСписок.Представление КАК СтатусТекст
ИЗ
Документ.ЗаказПокупателя КАК Документ
ЛЕВОЕ СОЕДИНЕНИЕ Перечисление.СтатусыДокументов.СписокЗначений КАК СтатусыСписок
ПО Документ.Статус = СтатусыСписок.Ссылка
Это снизит нагрузку на сервер, особенно при большом количестве записей.
Оптимизация запросов с перечислениями
Запросы с перечислениями могут работать медленно, если не учитывать особенности их хранения. Вот несколько советов по оптимизации:
1. Избегайте функции ПРЕДСТАВЛЕНИЕ в условиях
Функция ПРЕДСТАВЛЕНИЕ вычисляет строковое значение на лету, что замедляет выполнение запроса. Вместо:
ГДЕ ПРЕДСТАВЛЕНИЕ(Документ.Статус) = "Оплачено"
Используйте:
ГДЕ Документ.Статус = Перечисление.СтатусыДокументов.Оплачено
2. Используйте виртуальные таблицы для перечислений
Если нужно получить список всех возможных значений перечисления с их представлениями, используйте виртуальную таблицу Перечисление.Имя.СписокЗначений:
ВЫБРАТЬ
Статусы.Ссылка КАК Статус,
Статусы.Представление КАК Наименование
ИЗ
Перечисление.СтатусыДокументов.СписокЗначений КАК Статусы
3. Кэшируйте часто используемые перечисления
Если в коде часто обращаетесь к одним и тем же значениям перечислений, закэшируйте их в переменные:
СтатусОплачено = Перечисления.СтатусыДокументов.Оплачено;
СтатусОтгружено = Перечисления.СтатусыДокументов.Отгружено;
Это ускорит выполнение кода, особенно в циклах.
Самый быстрый способ работы с перечислениями в запросах — использование прямых ссылок (например, Перечисление.Имя.Значение). Функции вроде ПРЕДСТАВЛЕНИЕ или ВЫБОР замедляют выполнение, поэтому применяйте их только при необходимости.
FAQ: Частые вопросы по работе с перечислениями в 1С
Как получить все значения перечисления в запросе?
Используйте виртуальную таблицу Перечисление.ИмяПеречисления.СписокЗначений:
ВЫБРАТЬ
Значение КАК Ссылка,
Представление КАК Наименование
ИЗ
Перечисление.СтатусыДокументов.СписокЗначений
Этот запрос вернёт все возможные значения перечисления с их текстовыми представлениями.
Можно ли сравнивать перечисления из разных конфигураций?
Нет, сравнивать значения перечислений из разных конфигураций (или даже из разных баз) нельзя, даже если их имена совпадают. Перечисления привязаны к конкретной конфигурации и имеют уникальные внутренние идентификаторы. При обмене данными между базами используйте УИД или создавайте сопоставления значений.
Как узнать УИД значения перечисления?
УИД можно получить в конфигураторе или через встроенный язык:
Сообщить(Перечисления.СтатусыДокументов.Оплачено.УникальныйИдентификатор());
Или в запросе:
ВЫБРАТЬ
Значение КАК Ссылка,
Значение.УникальныйИдентификатор() КАК УИД
ИЗ
Перечисление.СтатусыДокументов.СписокЗначений КАК Значение
Почему запрос не находит документы с нужным статусом?
Возможные причины:
- В базе есть документы со статусом
Неопределено(проверьте условиеГДЕ Статус ЕСТЬ NULL). - Имя значения перечисления изменилось в конфигураторе, но в базе остались старые данные.
- Вы сравниваете по представлению, а в базе используется другой язык интерфейса.
Решение: используйте УИД для надёжного сравнения или проверьте состав перечисления в конфигураторе.
Как добавить новое значение в перечисление без потери данных?
Добавление нового значения в перечисление безопасно — оно не повлияет на существующие данные. Однако:
- 🔹 Удаление или переименование значений может привести к потере ссылочной целостности.
- 🔹 После изменения перечисления обновите кэш метаданных (
Конфигуратор → Администрирование → Обновить кэш метаданных). - 🔹 Если перечисление используется в регистрах или документах, проверьте, не появились ли записи с некорректными статусами.