Как исправить ошибку «Значение» в конструкции ВЫБОР КОГДА в запросе 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При написании запросов в платформе «1С:Предприятие» разработчики часто сталкиваются со сложной логикой ветвления данных. Для реализации условий непосредственно в теле запроса используется стандартная конструкция ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ. Однако при работе с перечислениями, справочниками или предопределенными элементами новички часто совершают типичную синтаксическую ошибку, которая приводит к отказу выполнения запроса СУБД.

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

Анализ проблемы: почему возникает ошибка?

Рассмотрим исходный фрагмент кода запроса, который вызвал затруднения у автора темы на форуме:


ВЫБОР
КОГДА
    Значение(Перечисление.ВидыОперацийРасходнаяНакладная.ВозвратСОтветХранения)
ТОГДА
    0
ИНАЧЕ
    ВТ_Маршрут.Накладная.СуммаДокумента - ЕСТЬNULL(ВложенныйЗапрос.Скидка, 0)
КОНЕЦ

При попытке сохранить или выполнить такой запрос платформа выдаст синтаксическую ошибку. Давайте выясним ее причину.

Конструкция ВЫБОР в языке запросов 1С является прямым аналогом оператора CASE WHEN в SQL. Главное правило ее использования заключается в следующем: после ключевого слова КОГДА всегда должно следовать логическое выражение (условие), результатом вычисления которого является тип Булево (то есть значение ИСТИНА или ЛОЖЬ).

В ошибочном примере кода сразу после слова КОГДА указана конструкция:

Значение(Перечисление.ВидыОперацийРасходнаяНакладная.ВозвратСОтветХранения)

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

Правильное написание условия в запросе

Чтобы исправить ошибку, нам необходимо превратить ссылку на значение перечисления в полноценное логическое выражение сравнения. Мы должны сопоставить конкретное поле из нашей таблицы базы данных с искомым значением перечисления с помощью оператора равенства «=».

Проанализируем правильный вариант написания конструкции ВЫБОР:


ВЫБОР 
    КОГДА ВТ_Маршрут.Накладная.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОперацийРасходнаяНакладная.ВозвратСОтветХранения)
        ТОГДА 0
    ИНАЧЕ ВТ_Маршрут.Накладная.СуммаДокумента - ЕСТЬNULL(ВложенныйЗапрос.Скидка, 0)
КОНЕЦ

В данном случае мы берем поле ВидОперации из связанной таблицы документа Накладная и сравниваем его со статическим значением перечисления. Результатом этого сравнения будет либо ИСТИНА, либо ЛОЖЬ, что полностью соответствует правилам синтаксиса оператора ВЫБОР.

Особенности работы с функцией ЗНАЧЕНИЕ()

Функция ЗНАЧЕНИЕ() (или её англоязычный аналог VALUE()) — это специализированная системная конструкция языка запросов 1С. Она предназначена для быстрого и прямого обращения к предопределенным элементам конфигурации без необходимости передавать их через параметры запроса.

Давайте выделим ключевые правила и ограничения при работе с этой функцией:

  1. Только статический путь: Внутри круглых скобок функции ЗНАЧЕНИЕ() можно указывать только жестко прописанные в конфигураторе имена объектов метаданных. Передавать переменные, вычисляемые поля или собирать строки динамически внутри этой функции категорически запрещено.
  2. Поддерживаемые типы данных: Функция умеет работать со следующими типами объектов:
    • Перечисления: ЗНАЧЕНИЕ(Перечисление.ИмяПеречисления.ИмяЗначения)
    • Предопределенные элементы справочников: ЗНАЧЕНИЕ(Справочник.Валюты.Рубль)
    • Предопределенные счета планов счетов: ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.Товары)
    • Предопределенные элементы планов видов характеристик.
    • Системные перечисления платформы, такие как направления движения накоплений: ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход) или ЗНАЧЕНИЕ(ВидДвиженияБухгалтерии.Дебет).
    • Пустые ссылки типов: ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка).
  3. Запрет на использование параметров: Написать конструкцию вида ЗНАЧЕНИЕ(&ИмяПараметра) нельзя. Если значение должно определяться динамически в коде на встроенном языке, вам следует отказаться от функции ЗНАЧЕНИЕ() в пользу стандартных параметров запроса.

Посмотрим на пример, когда значение перечисления передается в запрос динамически через параметр:


// В тексте запроса:
ВЫБОР 
    КОГДА ВТ_Маршрут.Накладная.ВидОперации = &ПараметрВидОперации
        ТОГДА 0
    ИНАЧЕ ВТ_Маршрут.Накладная.СуммаДокумента - ЕСТЬNULL(ВложенныйЗапрос.Скидка, 0)
КОНЕЦ

Затем во встроенном языке 1С мы передаем конкретную ссылку в этот параметр:


Запрос = Новый Запрос;
Запрос.Текст = "..."; // Текст запроса с параметром
Запрос.УстановитьПараметр("ПараметрВидОперации", Перечисления.ВидыОперацийРасходнаяНакладная.ВозвратСОтветХранения);
Результат = Запрос.Выполнить();

Оптимизация производительности при составных типах данных

Рассмотрим ситуацию, когда поле, к которому мы обращаемся, имеет составной тип данных. Например, поле Накладная в нашей временной таблице ВТ_Маршрут может хранить ссылки на различные документы: Документ.РасходнаяНакладная, Документ.ПеремещениеТоваров или Документ.ОтчетОРозничныхПродажах.

Когда мы пишем условие ВТ_Маршрут.Накладная.ВидОперации, СУБД вынуждена строить неявные левые соединения (LEFT JOIN) со всеми таблицами документов, входящих в этот составной тип, чтобы попытаться найти у них реквизит ВидОперации. Это крайне негативно сказывается на скорости выполнения запроса и может приводить к избыточному сканированию индексов и таблиц.

Чтобы избежать падения производительности, рекомендуется предварительно ограничивать тип проверяемого поля с помощью оператора ССЫЛКА. Проанализируем оптимизированный вариант условия:


ВЫБОР 
    КОГДА ВТ_Маршрут.Накладная ССЫЛКА Документ.РасходнаяНакладная 
          И ВТ_Маршрут.Накладная.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОперацийРасходнаяНакладная.ВозвратСОтветХранения)
        ТОГДА 0
    ИНАЧЕ ВТ_Маршрут.Накладная.СуммаДокумента - ЕСТЬNULL(ВложенныйЗапрос.Скидка, 0)
КОНЕЦ

Благодаря явному указанию типа через ССЫЛКА Документ.РасходнаяНакладная транслятор запросов 1С точно определит, к какой физической таблице базы данных нужно обратиться для проверки реквизита ВидОперации. Лишние неявные соединения с другими таблицами документов создаваться не будут.

Редкая форма конструкции ВЫБОР (аналог Switch/Case)

Мало кто из начинающих разработчиков знает, что в языке запросов 1С поддерживается альтернативный синтаксис конструкции ВЫБОР. Он очень похож на классический оператор switch или case в традиционных языках программирования (например, C#, Java или JavaScript). Он позволяет указать проверяемое поле сразу после ключевого слова ВЫБОР, избавляя от необходимости дублировать имя этого поля в каждом условии КОГДА.

Давайте посмотрим на пример такой реализации:


ВЫБОР ВТ_Маршрут.Накладная.ВидОперации
    КОГДА ЗНАЧЕНИЕ(Перечисление.ВидыОперацийРасходнаяНакладная.ВозвратСОтветХранения) ТОГДА 0
    КОГДА ЗНАЧЕНИЕ(Перечисление.ВидыОперацийРасходнаяНакладная.РеализацияКлиенту) ТОГДА 1
    ИНАЧЕ 2
КОНЕЦ

Преимущества данного подхода:

Ограничения:

Получение строкового представления перечисления в запросе

В практической работе иногда возникает задача вывести текстовое имя перечисления (его идентификатор или синоним) для последующей выгрузки во внешние системы (например, через форматы XML, JSON или XLS).

Важно помнить, что напрямую получить строковое имя значения перечисления (например, получить строку "ВозвратСОтветХранения") стандартными средствами запроса невозможно. База данных хранит лишь внутренние идентификаторы (ссылки).

Однако мы можем решить эту задачу двумя способами:

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


ВЫБРАТЬ 
    ПРЕДСТАВЛЕНИЕ(ВТ_Маршрут.Накладная.ВидОперации) КАК ТекстовоеПредставлениеОперации
ИЗ
    ВТ_Маршрут КАК ВТ_Маршрут

Способ 2. Жесткое сопоставление через ВЫБОР КОГДА. Если вам необходим именно системный код (идентификатор) значения для интеграции, то придется прописать его вручную в запросе:


ВЫБРАТЬ
    ВЫБОР 
        КОГДА ВТ_Маршрут.Накладная.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОперацийРасходнаяНакладная.ВозвратСОтветХранения)
            ТОГДА "ВозвратСОтветХранения"
        КОГДА ВТ_Маршрут.Накладная.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОперацийРасходнаяНакладная.Продажа)
            ТОГДА "Продажа"
        ИНАЧЕ "Прочее"
    КОНЕЦ КАК СистемныйКодОперации
ИЗ
    ВТ_Маршрут КАК ВТ_Маршрут

Резюме и правила хорошего тона

Подведем итоги и зафиксируем правила, которые помогут вам избежать ошибок при написании условных выражений в запросах 1С:

← На главную