Как в запросе 1С в конструкции ВЫБОР КОГДА указать условие по конкретному элементу справочника

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

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

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

Способ 1. Использование параметров запроса (Рекомендуемый)

Наиболее правильным и гибким способом является передача ссылки на нужный элемент через параметр. Это позволяет избежать «хардкода» (жесткого прописывания значений) непосредственно в тексте запроса и делает код более универсальным.

Проанализируем пример реализации. Сначала мы находим нужный нам элемент в программном коде, а затем передаем его в запрос:


// Сначала находим ссылку на нужный склад
СсылкаНаСклад = Справочники.Склады.НайтиПоКоду("000000001");

// Создаем запрос и устанавливаем параметр
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Рег.Номенклатура,
    |    ВЫБОР
    |        КОГДА Рег.Склад = &НужныйСклад ТОГДА ""СпецХранение""
    |        ИНАЧЕ ""ОбщийСклад""
    |    КОНЕЦ КАК КатегорияСклада
    |ИЗ
    |    РегистрНакопления.ТоварыНаСкладах.Остатки КАК Рег";

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

Преимущества этого метода:

  1. Высокая производительность: сравнение идет по внутреннему идентификатору (ссылке), что в СУБД обрабатывается максимально быстро.
  2. Надежность: если пользователь изменит код или наименование склада, ссылка останется прежней, и запрос продолжит работать корректно.
  3. Гибкость: значение параметра можно вынести в настройки пользователя или константы.

Способ 2. Использование функции ЗНАЧЕНИЕ() для предопределенных элементов

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

Разберем, как это выглядит на практике:


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

Важно помнить: этот метод работает только для тех элементов, которые заведены в дереве метаданных конфигурации. Для обычных элементов, созданных пользователями в режиме «1С:Предприятие», функция ЗНАЧЕНИЕ() недоступна.

Способ 3. Сравнение по коду или наименованию

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


"ВЫБРАТЬ
|    Обороты.Регистратор,
|    ВЫБОР
|        КОГДА Обороты.Регистратор.Склад.Код = ""007"" ТОГДА ""Склад Агента""
|        ИНАЧЕ ""Прочие""
|    КОНЕЦ КАК Статус
|ИЗ
|    РегистрНакопления.Продажи.Обороты КАК Обороты"

Хотя этот метод кажется простым и не требует установки параметров, мы крайне не рекомендуем использовать его в промышленной разработке. Выясним причину: сравнение строк в запросах происходит медленнее, чем сравнение ссылок. Кроме того, любое изменение длины кода или переименование элемента приведет к тому, что условие перестанет выполняться, а программа не выдаст никакой ошибки — данные просто перестанут попадать в нужную ветку условия.

Разбор критических ошибок производительности: точка от Регистратора

В обсуждениях часто встречается конструкция вида Регистратор.Склад. Посмотрим на ситуацию глубже. В системе 1С Регистратор является составным типом данных. Когда мы обращаемся к реквизиту через точку от регистратора, СУБД вынуждена выполнять операцию LEFT JOIN (левое соединение) со всеми таблицами документов, которые могут делать записи в этот регистр.

Если в вашем регистре 50 видов документов-регистраторов, ваш запрос превратится в «монстра», соединяющего 50 таблиц. Чтобы избежать падения производительности, воспользуемся функцией ВЫРАЗИТЬ():


"ВЫБОР
|    КОГДА ВЫРАЗИТЬ(Обороты.Регистратор КАК Документ.РеализацияТоваровУслуг).Склад = &ПараметрСклад
|    ТОГДА ...
|КОНЕЦ"

Это заставит систему обращаться только к одной конкретной таблице документа, что существенно ускорит выполнение запроса.

Альтернатива для сложных систем: Дополнительные реквизиты

Проанализируем ситуацию, когда элементов, попадающих под условие, может быть много или они могут меняться. Вместо того чтобы перечислять их в запросе или коде, лучше добавить в справочник Склады новый реквизит типа Булево (например, ЭтоТорговаяТочка).

Тогда наше условие в запросе станет изящным и независимым от конкретных ссылок:


"ВЫБОР
|    КОГДА Обороты.Склад.ЭтоТорговаяТочка ТОГДА ""Розничная выручка""
|    ИНАЧЕ ""Прочая выручка""
|КОНЕЦ"

Этот подход считается признаком «хорошего тона» в архитектуре 1С, так как позволяет бизнес-пользователям самостоятельно управлять логикой отчетов, просто устанавливая флажки в элементах справочника, без привлечения программиста для правки кода.

Итоги

Подводя итог, выделим основные правила использования условий по элементам в запросах:

  1. Всегда отдавайте предпочтение параметрам запроса для передачи ссылок.
  2. Используйте ЗНАЧЕНИЕ() только для предопределенных элементов.
  3. Избегайте сравнения по коду или наименованию в текстах запросов.
  4. При обращении к реквизитам через Регистратор всегда используйте ВЫРАЗИТЬ().
  5. Для сложной или часто меняющейся логики используйте дополнительные реквизиты-признаки в самих справочниках.
← На главную