В процессе разработки на платформе 1С часто возникают две связанные задачи: как в запросе вывести понятное пользователю текстовое представление значения перечисления (например, "НДС 20%" вместо системной ссылки) и как выполнить обратную операцию — найти в базе данных записи, соответствующие определенной строке (например, найти все документы со ставкой НДС "20%"). Рассмотрим подробно несколько способов решения этих задач, их преимущества и недостатки. Для этой задачи есть консоль запросов и кода разработчика.
Самый простой и прямой способ получить в запросе пользовательское представление (синоним) значения перечисления — это использовать функцию ПРЕДСТАВЛЕНИЕ(). Она преобразует ссылочное значение в его строковый эквивалент, заданный в конфигураторе.
Посмотрим на пример. Чтобы получить список всех значений перечисления СтавкиНДС и их синонимы, можно использовать следующий запрос:
ВЫБРАТЬ
СтавкиНДС.Ссылка КАК СсылкаНаПеречисление,
ПРЕДСТАВЛЕНИЕ(СтавкиНДС.Ссылка) КАК ПредставлениеНДС
ИЗ
Перечисление.СтавкиНДС КАК СтавкиНДС
Результатом будет таблица с двумя колонками: одна с системной ссылкой, другая — с понятным текстом ("Без НДС", "НДС 0%", "НДС 10%", "НДС 20%" и т.д.). Этот метод идеально подходит для вывода данных в отчеты и динамические списки.
Важный момент: Использование функции ПРЕДСТАВЛЕНИЕ() в условии ГДЕ крайне не рекомендуется. Например, такой запрос будет работать очень медленно на больших объемах данных:
// Пример НЕЭФФЕКТИВНОГО запроса
ВЫБРАТЬ
ДокументПродажи.Ссылка
ИЗ
Документ.РеализацияТоваровУслуг КАК ДокументПродажи
ГДЕ
ПРЕДСТАВЛЕНИЕ(ДокументПродажи.СтавкаНДС) = &НДССтрокой
Причина низкой производительности в том, что ПРЕДСТАВЛЕНИЕ() — это функция языка 1С, а не SQL. Система сначала получит из базы данных все записи, и только потом, на уровне сервера 1С, будет применять фильтр к текстовому представлению. Это лишает СУБД возможности использовать индексы для быстрого поиска.
Если вам нужно в самом запросе сопоставить значения перечисления с определенными строками, можно использовать конструкцию ВЫБОР КОГДА ... ТОГДА ... КОНЕЦ. Этот подход позволяет "захардкодить" логику прямо в тексте запроса.
Этот метод может быть полезен, когда нужно не просто получить представление, а, например, сгруппировать значения или присвоить им какой-то признак.
ВЫБРАТЬ
СтавкиНДС.Ссылка,
ВЫБОР
КОГДА СтавкиНДС.Ссылка = ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.НДС20)
ТОГДА "Ставка 20 процентов"
КОГДА СтавкиНДС.Ссылка = ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.НДС10)
ТОГДА "Ставка 10 процентов"
КОГДА СтавкиНДС.Ссылка = ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.БезНДС)
ТОГДА "Без налога"
ИНАЧЕ "Другая ставка"
КОНЕЦ КАК ОписаниеСтавки
ИЗ
Перечисление.СтавкиНДС КАК СтавкиНДС
Преимущества:
Недостатки:
ИНАЧЕ.Как мы выяснили, фильтровать по представлению в запросе неэффективно. Правильный подход — найти нужную ссылку на перечисление средствами языка 1С до выполнения запроса и передать ее в качестве параметра.
Для этого можно создать вспомогательную функцию (поможет отладка кода в режиме Предприятие), которая будет искать значение перечисления по его синониму или имени, перебирая метаданные.
Пример поиска по синониму:
&НаСервере
Функция НайтиСтавкуНДСПоПредставлению(ИскомоеПредставление)
Для Каждого ЗначениеПеречисления Из Метаданные.Перечисления.СтавкиНДС.Значения() Цикл
// Сравниваем синоним из метаданных с искомой строкой
Если НРег(ЗначениеПеречисления.Синоним) = НРег(ИскомоеПредставление) Тогда
// Возвращаем ссылку на найденное значение
Возврат Перечисления.СтавкиНДС[ЗначениеПеречисления.Имя];
КонецЕсли;
КонецЦикла;
// Если ничего не найдено
Возврат Перечисления.СтавкиНДС.ПустаяСсылка();
КонецФункции
// Пример использования
&НаКлиенте
Процедура ВыполнитьЗапрос()
СтрокаНДС = "20%"; // Строка, по которой ищем
НайденнаяСтавка = НайтиСтавкуНДСПоПредставлению(СтрокаНДС);
Если НЕ НайденнаяСтавка.Пустая() Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.СтавкаНДС = &СтавкаНДС";
Запрос.УстановитьПараметр("СтавкаНДС", НайденнаяСтавка);
Результат = Запрос.Выполнить().Выгрузить();
// Дальнейшая обработка результата
КонецЕсли;
КонецПроцедуры
Этот подход является наиболее производительным и правильным с точки зрения архитектуры, так как позволяет СУБД использовать индекс по полю перечисления для максимально быстрого отбора данных.
В ситуациях, когда нужно сопоставить большое количество строк со значениями перечислений, отличным решением будет использование временных таблиц. Этот метод сочетает гибкость программной подготовки данных и мощь соединений в запросах.
Разберем по шагам:
ЛЕВОЕ СОЕДИНЕНИЕ с временной таблицей по строковому полю.Посмотрим на пример:
// 1, 2. Создаем и заполняем таблицу значений
ТаблицаСоответствия = Новый ТаблицаЗначений;
ТаблицаСоответствия.Колонки.Добавить("НДССтрокой", Новый ОписаниеТипов("Строка"));
ТаблицаСоответствия.Колонки.Добавить("СсылкаНаПеречисление", Новый ОписаниеТипов("ПеречислениеСсылка.СтавкиНДС"));
НоваяСтрока = ТаблицаСоответствия.Добавить();
НоваяСтрока.НДССтрокой = "20%";
НоваяСтрока.СсылкаНаПеречисление = Перечисления.СтавкиНДС.НДС20;
НоваяСтрока = ТаблицаСоответствия.Добавить();
НоваяСтрока.НДССтрокой = "Без налога";
НоваяСтрока.СсылкаНаПеречисление = Перечисления.СтавкиНДС.БезНДС;
// 3. Передаем в запрос
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст = "ВЫБРАТЬ
| ТЗ.НДССтрокой,
| ТЗ.СсылкаНаПеречисление
|ПОМЕСТИТЬ ВТ_СоответствиеНДС
|ИЗ
| &ТаблицаСоответствия КАК ТЗ;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Продажи.Номенклатура,
| Продажи.Сумма,
| ВТ_СоответствиеНДС.СсылкаНаПеречисление
|ИЗ
| РегистрНакопления.Продажи КАК Продажи
| ЛЕВОЕ СОЕДИНЕНИЕ ВТ_СоответствиеНДС
| ПО Продажи.ПредставлениеСтавкиНДС = ВТ_СоответствиеНДС.НДССтрокой"; // Предполагаем, что в регистре есть строковое поле
Запрос.УстановитьПараметр("ТаблицаСоответствия", ТаблицаСоответствия);
Результат = Запрос.Выполнить();
Этот метод очень гибок, так как вся логика сопоставления вынесена в код и не требует изменения текста запроса.
Если задача стоит в контексте обмена данными между разными базами (например, УТ и БП), то полагаться на синонимы (ПРЕДСТАВЛЕНИЕ()) категорически нельзя. Синоним может быть изменен пользователем, он зависит от языка конфигурации и не является надежным идентификатором.
Для надежного обмена данными следует использовать инвариантные (неизменяемые) свойства:
Строка(Перечисления.СтавкиНДС.НДС20) вернет "НДС20".Перечисления.СтавкиНДС["НДС20"] вернет ссылку на нужное значение.Порядок(). Этот способ тоже рабочий, но менее надежен, чем имя, так как теоретически порядок значений в перечислении может измениться при обновлении конфигурации, хотя на практике это случается редко.Вывод: для надежного обмена данными всегда передавайте имя значения перечисления, а не его синоним или строковое представление.