Как в запросе 1С наложить условие на несколько значений перечисления?

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

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

В этой статье мы подробно разберем, как правильно составить такие условия, рассмотрим различные подходы и выясним, какой из них является наиболее эффективным с точки зрения производительности СУБД.

Способ 1. Использование оператора «В» со списком значений

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

Разберем конкретный пример синтаксиса:


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

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

Способ 2. Использование логического оператора «ИЛИ»

Если по каким-то причинам использование оператора В кажется неудобным, можно прибегнуть к классическому сравнению через ИЛИ. В этом случае каждое условие должно быть полным (поле — оператор — значение).

Проанализируем такой вариант кода:


ГДЕ
    (ЧекККМ.СтатусЧекаККМ = ЗНАЧЕНИЕ(Перечисление.СтатусыЧековККМ.Архивный)
    ИЛИ ЧекККМ.СтатусЧекаККМ = ЗНАЧЕНИЕ(Перечисление.СтатусыЧековККМ.Пробитый))

Хотя этот вариант является рабочим, в сообществе разработчиков 1С за ним закрепилась репутация «не самого удачного решения». Это связано с тем, как СУБД (особенно MS SQL Server) строит план выполнения запроса — здесь поможет инструмент анализа планов выполнения СУБД. Использование множественных ИЛИ в некоторых сложных запросах может сбить оптимизатор с толку, что приведет к полному сканированию таблицы (Index Scan) вместо быстрого поиска по индексу (Index Seek).

Способ 3. Передача списка значений через параметры (лучшая практика)

В реальной разработке жесткое кодирование (hardcode) значений перечисления прямо в тексте запроса считается не самым лучшим тоном, если логика фильтрации может измениться. Гораздо профессиональнее передавать массив нужных значений в качестве параметра.

Давайте посмотрим, как это реализовать по шагам:

  1. Сначала в программном коде сформируем массив со значениями перечисления.
  2. Затем передадим этот массив в запрос как параметр.

Пример кода на языке 1С (удобно использовать консоль запросов): — для этого подойдет многофункциональная консоль запросов и кода.


// Формируем список нужных статусов
МассивСтатусов = Новый Массив;
МассивСтатусов.Добавить(Перечисления.СтатусыЧековККМ.Архивный);
МассивСтатусов.Добавить(Перечисления.СтатусыЧековККМ.Пробитый);

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

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

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

Анализ производительности: почему «ИЛИ» — это риск?

Рассмотрим техническую сторону вопроса. Когда мы пишем В (&Список), платформа 1С транслирует это в SQL-оператор IN (...). Большинство современных систем управления базами данных отлично оптимизируют такие конструкции.

Если же мы используем ИЛИ, особенно в сочетании с другими сложными фильтрами или соединениями таблиц, СУБД может выбрать неоптимальный план. Это критически важно для высоконагруженных систем. В стандартах разработки 1С рекомендуется избегать ИЛИ в секции ГДЕ, если условие можно переписать через оператор В или через объединение нескольких запросов (ОБЪЕДИНИТЬ ВСЕ).

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

Работа с временными таблицами для фильтрации

В ситуациях, когда список значений для фильтра очень велик (например, сотни или тысячи элементов), использование оператора В может замедлиться. В таких случаях мы рекомендуем использовать временные таблицы:

  1. Поместите список необходимых значений перечисления во временную таблицу.
  2. Выполните ВНУТРЕННЕЕ СОЕДИНЕНИЕ основной таблицы (например, ЧекККМ) с этой временной таблицей по полю статуса.

Для СУБД соединение двух таблиц по индексированным полям зачастую является самой быстрой операцией. Это гарантирует, что поиск будет выполнен максимально эффективно.

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

← На главную