К статье
Практический материал

Разработка и Конфигурация · 11 мин

Множественный выбор в запросе 1С: оператор В и конструкция КОГДА

Как в запросе 1С сделать выбор по списку значений через В и условную логику через КОГДА-ТОГДА-ИНАЧЕ. Синтаксис, примеры кода, ошибки и проверка результата.

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

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

Материал ориентирован на разработчиков и внедренцев, работающих в конфигураторе или консоли запросов. Примеры приведены на встроенном языке запросов 1С:Предприятия 8 и подходят для большинства типовых и самописных конфигураций.

Как работает оператор В для множественного выбора

Оператор В проверяет, входит ли значение поля в заданный набор. Самый простой вариант — перечислить значения прямо в тексте запроса: ГДЕ Склад В ("Основной", "Розничный"). Такой вариант подходит для фиксированных наборов, но на практике чаще нужен динамический список, который пользователь отобрал в форме.

Для динамического набора в оператор В передаётся параметр, содержащий массив или список значений: ГДЕ Номенклатура В (&СписокНоменклатуры). Перед выполнением запроса параметр заполняется кодом: Запрос.УстановитьПараметр("СписокНоменклатуры", МассивНоменклатуры);. Платформа сама разворачивает массив в условие отбора на уровне СУБД.

Важно понимать: В — это логическое «ИЛИ» по всем элементам списка. Запись ГДЕ Организация В (&Организации) эквивалентна цепочке Организация = &Орг1 ИЛИ Организация = &Орг2 ИЛИ .... Если нужно, чтобы строка соответствовала нескольким условиям одновременно по разным полям, каждое поле фильтруется своим оператором В, объединённым через И.

bsl
ВЫБРАТЬ
	Продажи.Номенклатура КАК Номенклатура,
	СУММА(Продажи.Количество) КАК Количество
ИЗ
	РегистрНакопления.Продажи КАК Продажи
ГДЕ
	Продажи.Номенклатура В (&СписокНоменклатуры)
	И Продажи.Период МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО
	Продажи.Номенклатура

Передача списка значений в параметр запроса

Корректная передача параметра — самое частое место ошибок. В параметр можно передать массив, список значений или таблицу значений (через временную таблицу). Строку с перечислением через запятую передавать нельзя: платформа воспримет её как одно строковое значение, и отбор ничего не найдёт либо упадёт с ошибкой несоответствия типов.

Типовой код подготовки параметра выглядит так: сначала формируется массив ссылок (например, из отбора компоновки данных или из табличной части), затем он передаётся в запрос. Если элементы приходят из пользовательского списка значений, его можно передать напрямую — платформа принимает и СписокЗначений.

Порядок действий
  1. 1
    Сформируйте массив или список значений с нужными ссылками
  2. 2
    В тексте запроса напишите условие ГДЕ Поле В (&ИмяПараметра)
  3. 3
    Вызовите Запрос.УстановитьПараметр("ИмяПараметра", Массив)
  4. 4
    Выполните запрос и проверьте результат в консоли запросов
  5. 5
    Убедитесь, что количество строк совпадает с ожидаемым отбором

Если отбор нужен по иерархии (например, по группе номенклатуры со всеми вложенными элементами), используется вариант В ИЕРАРХИИ (&Группы). Это избавляет от необходимости программно собирать все подчинённые элементы — СУБД сделает это сама.

Конструкция ВЫБОР КОГДА — условная логика в полях запроса

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

Типичный сценарий — присвоение текстового статуса по числовому условию: ВЫБОР КОГДА Остаток < 0 ТОГДА "Дефицит" КОГДА Остаток = 0 ТОГДА "Нет на складе" ИНАЧЕ "В наличии" КОНЕЦ КАК Статус. Такое поле удобно выводить в отчёт вместо постобработки выборки кодом.

Обратите внимание на типы: все ветки ТОГДА и ИНАЧЕ должны возвращать совместимые типы. Если в одной ветке строка, а в другой число, при дальнейшем использовании поля (например, в группировке или соединении) можно получить непредсказуемый результат или ошибку. Если ветка ИНАЧЕ опущена и ни одно условие не сработало, поле получит значение NULL — это частая причина «пропавших» данных при соединениях.

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

Комбинация: множественный выбор внутри условия КОГДА

Оператор В можно использовать прямо внутри условия КОГДА. Это удобно, когда нужно разметить строки по принадлежности к разным спискам: ВЫБОР КОГДА Номенклатура В (&АкционныйТовар) ТОГДА "Акция" КОГДА Номенклатура В (&Новинки) ТОГДА "Новинка" ИНАЧЕ "Обычный" КОНЕЦ. Каждый список передаётся отдельным параметром-массивом.

Тот же приём работает в секции ГДЕ и в условиях соединений. Например, соединение с таблицей цен только для определённого набора видов цен: ЛЕВОЕ СОЕДИНЕНИЕ ... ПО Цены.ВидЦены В (&ВидыЦен) И Цены.Номенклатура = Товары.Ссылка. Такой фильтр в условии соединения обычно эффективнее, чем фильтрация уже соединённого результата.

Для сложных условий с несколькими списками и диапазонами иногда читабельнее вынести логику во временную таблицу: сначала поместить в неё список с признаком, затем соединиться с ней. Это упрощает отладку — содержимое временной таблицы можно посмотреть отдельным запросом.

Сравнение вариантов

В (&Параметр) с массивом

Быстро и просто для одного списка; ограничение — у очень больших списков возможно падение производительности на некоторых СУБД

Временная таблица + соединение

Подходит для больших списков и когда к каждому элементу нужны дополнительные поля; требует больше кода

ВЫБОР КОГДА с перечислением

Хорош для малого фиксированного набора условий; неудобен при динамических списках

Иерархический отбор В ИЕРАРХИИ

Правильный выбор для групп справочников; не работает с произвольными наборами значений

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

Передача очень большого массива (тысячи элементов) в параметр В может замедлить запрос: СУБД строит длинное условие ИЛИ или большой временный набор. Признак проблемы — резкий рост времени выполнения при увеличении списка. В таких случаях список выгружают во временную таблицу через параметр-таблицу значений и делают внутреннее соединение: оптимизатор СУБД справляется с соединением заметно лучше.

Ещё одно ограничение: в запросах к виртуальным таблицам регистров (Остатки, Обороты) параметры отбора лучше передавать в параметры виртуальной таблицы, а не в секцию ГДЕ основного запроса. Отбор в параметрах виртуальной таблицы выполняется до вычисления итогов, что существенно сокращает объём обрабатываемых данных.

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

Как проверить результат и типичные ошибки

Базовая проверка — выполнить запрос в консоли запросов с теми же параметрами, что и в коде, и сверить количество строк с ожиданием. Если результат пустой, первым делом смотрите, что реально попало в параметр: выведите массив в сообщение или проверьте через отладчик. Пустой массив в В (&Параметр) даёт пустой результат без какой-либо ошибки — это ловушка номер один.

Вторая группа проверок касается типов. Если в массиве строки, а поле отбора — ссылка на справочник, сравнение не сработает. Убедитесь, что элементы массива имеют тот же тип, что и поле. Для ВЫБОР проверяйте, что ветка ИНАЧЕ задана, иначе непокрытые строки получат NULL и могут «выпасть» из соединений и группировок.

Типичные ошибки
01
Передача строки с перечислением значений вместо массива — параметр трактуется как одно значение, отбор не срабатывает
02
Пустой массив в параметре — запрос возвращает ноль строк без ошибки, причину ищут часами
03
Отсутствие ИНАЧЕ в ВЫБОР КОГДА — непокрытые строки получают NULL и теряются при соединениях
04
Несовместимые типы в ветках ТОГДА — ошибка при выполнении или неверная группировка
05
Отбор по списку в ГДЕ вместо параметров виртуальной таблицы — лишнее чтение итогов и медленный запрос
Контрольные точки

Как проверить результат

Количество строк результата
Норма

Совпадает с числом документов/элементов по отобранному списку

Тревожный признак

Ноль строк или заметно меньше ожидаемого — проверяйте параметр

Содержимое параметра-массива
Норма

Массив заполнен ссылками нужного типа

Тревожный признак

Массив пуст, содержит строки или NULL

Вычисляемое поле ВЫБОР КОГДА
Норма

Все строки имеют осмысленное значение

Тревожный признак

Часть строк содержит NULL — нет ветки ИНАЧЕ

Время выполнения
Норма

Запрос отрабатывает за секунды на рабочем объёме

Тревожный признак

Время резко растёт с размером списка — переходите на временную таблицу

FAQ

Можно ли передать в параметр В список значений с формы?

Да, СписокЗначений передаётся в параметр напрямую, без преобразования в массив. Платформа сама извлечёт значения элементов. Главное — чтобы в списке были сами ссылки или примитивные значения, а не представления.

Чем отличается В от В ИЕРАРХИИ?

Оператор В проверяет точное совпадение с элементами списка. В ИЕРАРХИИ дополнительно включает все подчинённые элементы, если в списке указана группа справочника. Для неиерархических данных В ИЕРАРХИИ работает как обычный В.

Почему запрос с В (&Параметр) возвращает пустой результат без ошибки?

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

Можно ли использовать ВЫБОР КОГДА в секции ГДЕ?

Технически да, но делать это стоит редко: условие через ВЫБОР обычно не может использовать индексы, и запрос замедляется. Практичнее переписать условие через И/ИЛИ по исходным полям, а ВЫБОР оставить для вычисляемых колонок результата.

Что делать, если список для отбора содержит десятки тысяч элементов?

Передайте список как таблицу значений в параметр, поместите её во временную таблицу (ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ) и выполните внутреннее соединение с основной таблицей. Для временной таблицы полезно создать индекс по полю соединения — это заметно ускоряет запрос на больших объёмах.

Как в ВЫБОР КОГДА обработать NULL в поле?

Прямое сравнение с NULL не сработает — используйте конструкцию КОГДА Поле ЕСТЬ NULL ТОГДА .... Либо заранее оберните поле функцией ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) и сравнивайте уже с конкретным значением.

Итог

Что важно запомнить

Множественный отбор делается оператором В с параметром-массивом, условная логика — конструкцией ВЫБОР КОГДА с обязательной веткой ИНАЧЕ. Пустой параметр молча даёт пустой результат, а большие списки выгоднее передавать через временную таблицу с соединением.