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

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

Оператор В в запросах 1С: как фильтровать данные по списку значений

Как использовать оператор В в запросах 1С: фильтрация по списку значений, вложенные запросы, проверка иерархии, параметры и типичные ошибки с примерами кода.

Оператор В (IN) в языке запросов 1С проверяет, входит ли значение поля в заданный набор: список констант, результат вложенного запроса или таблицу значений, переданную через параметр. Это один из самых востребованных инструментов при отборе данных: он заменяет длинные цепочки условий через ИЛИ и позволяет строить гибкие отборы по произвольному количеству элементов.

Типичная задача выглядит так: нужно выбрать документы по нескольким контрагентам, товары из определённых групп номенклатуры или сотрудников конкретных подразделений. Вместо конструкции Контрагент = &К1 ИЛИ Контрагент = &К2 ИЛИ ... пишется одно условие Контрагент В (&СписокКонтрагентов), а список передаётся параметром из кода.

У оператора есть важные особенности: поведение с NULL-значениями, работа с иерархическими справочниками через В ИЕРАРХИИ, ограничения производительности при больших списках и нюансы типизации параметров. Ниже разобраны все основные сценарии с рабочими примерами.

Базовый синтаксис оператора В

Простейшая форма — перечисление значений прямо в тексте запроса через запятую в круглых скобках:

ВЫБРАТЬ

Номенклатура.Ссылка КАК Товар,

Номенклатура.Наименование

ИЗ

Справочник.Номенклатура КАК Номенклатура

ГДЕ

Номенклатура.ВидНоменклатуры В (&Вид1, &Вид2, &Вид3)

Оператор возвращает ИСТИНУ, если значение поля совпадает хотя бы с одним элементом списка. Логически это эквивалентно цепочке равенств через ИЛИ, но запись короче и оптимизатор СУБД обычно обрабатывает её эффективнее.

Существует и обратная форма — НЕ В (NOT IN), которая отбирает записи, не входящие в список. С ней связана главная ловушка: если в списке или в проверяемом поле встречается NULL, результат может оказаться неожиданным (подробности — в разделе об ошибках).

Фильтрация по списку значений из параметра

На практике список значений почти всегда формируется динамически в коде модуля и передаётся в запрос параметром. Платформа позволяет передать массив, список значений или таблицу значений — все они корректно разворачиваются в условие В.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| РеализацияТоваровУслуг.Ссылка КАК Документ,

| РеализацияТоваровУслуг.СуммаДокумента

|ИЗ

| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

|ГДЕ

| РеализацияТоваровУслуг.Контрагент В (&СписокКонтрагентов)

| И РеализацияТоваровУслуг.Проведен";

СписокКонтрагентов = Новый СписокЗначений;

СписокКонтрагентов.Добавить(Контрагент1);

СписокКонтрагентов.Добавить(Контрагент2);

Запрос.УстановитьПараметр("СписокКонтрагентов", СписокКонтрагентов);

Результат = Запрос.Выполнить().Выгрузить();

Ключевое требование — тип элементов списка должен совпадать с типом поля. Если поле имеет составной тип (например, «Контрагент или Договор»), а в списке есть значения другого типа, платформа не выдаст ошибку, но сравнение по несовпадающим типам даст ЛОЖЬ, и данные «потеряются» молча. Это одна из самых коварных причин «пустого» результата запроса.

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

Оператор В с вложенным запросом

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

ВЫБРАТЬ

Заказы.Ссылка КАК Заказ,

Заказы.Контрагент

ИЗ

Документ.ЗаказКлиента КАК Заказы

ГДЕ

Заказы.Контрагент В

(ВЫБРАТЬ РАЗЛИЧНЫЕ

Продажи.Контрагент

ИЗ

РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Продажи

ГДЕ

Продажи.СуммаОборот > 0)

Вложенный запрос должен возвращать ровно одно поле — иначе платформа выдаст ошибку при исполнении. Рекомендуется использовать РАЗЛИЧНЫЕ во вложенном запросе: дубликаты не влияют на результат, но увеличивают объём обрабатываемых данных.

По производительности конструкция с вложенным запросом часто уступает соединению таблиц (ЛЕВОЕ СОЕДИНЕНИЕ с проверкой на NULL или ВНУТРЕННЕЕ СОЕДИНЕНИЕ). Если запрос работает медленно на больших объёмах, перепишите условие В через соединение и сравните план выполнения.

Способы задать набор значений для оператора В

Константы в скобках

Подходит для фиксированных коротких списков, известных на этапе написания запроса. Не подходит для динамических отборов.

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

Основной вариант для отборов из кода и пользовательских настроек. Ограничение: при очень больших списках возможно падение производительности.

Вложенный запрос

Когда набор вычисляется из данных базы. Требует ровно одного поля в выборке; на больших таблицах может уступать соединению.

Таблица значений через временную таблицу

Оптимально для больших списков: таблица помещается во временную, затем используется соединение. Требует больше кода, но работает быстрее.

Оператор В ИЕРАРХИИ для справочников

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

ВЫБРАТЬ

Номенклатура.Ссылка КАК Товар

ИЗ

Справочник.Номенклатура КАК Номенклатура

ГДЕ

Номенклатура.Ссылка В ИЕРАРХИИ (&ГруппаТоваров)

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

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

Проверка вхождения через временные таблицы

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

Запрос = Новый Запрос;

Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

Запрос.Текст =

"ВЫБРАТЬ

| Таб.Контрагент

|ПОМЕСТИТЬ ВТ_Контрагенты

|ИЗ

| &ТаблицаКонтрагентов КАК Таб

|ИНДЕКСИРОВАТЬ ПО

| Контрагент

|;

|ВЫБРАТЬ

| Док.Ссылка

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Док

|ГДЕ

| Док.Контрагент В (ВЫБРАТЬ Контрагент ИЗ ВТ_Контрагенты)";

Запрос.УстановитьПараметр("ТаблицаКонтрагентов", ТаблицаКонтрагентов);

Предложение ИНДЕКСИРОВАТЬ ПО ускоряет последующее соединение или проверку вхождения, особенно на больших временных таблицах. Это один из немногих способов явно влиять на производительность запросов в 1С, и пренебрегать им при больших объёмах не стоит.

Типичные ошибки и поведение с NULL

Самая частая проблема — пустой результат из-за несовпадения типов. Например, в параметр передали массив строк, а поле имеет тип «СправочникСсылка». Запрос выполнится без ошибок, но ничего не найдёт. Всегда проверяйте типы элементов списка перед выполнением.

Вторая ловушка — NULL. Если проверяемое поле содержит NULL (например, из-за левого соединения), то условие Поле В (&Список) даст NULL, а не ИСТИНА, и запись не попадёт в результат. С конструкцией НЕ В ситуация ещё тоньше: если сам список содержит NULL (что возможно при вложенном запросе), результат условия становится неопределённым, и отбор может вернуть пустую выборку там, где ожидались данные.

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

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

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

При небольшом числе элементов (единицы — десятки значений) оператор В с параметром работает быстро и не требует оптимизации. Проблемы начинаются на списках из тысяч значений: запрос компилируется в длинное условие, и время подготовки и выполнения заметно растёт. Признак проблемы — запрос, который на тестовых данных выполнялся мгновенно, «зависает» в рабочей базе.

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

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

Маршрут решения

Как выбрать реализацию отбора

Значений меньше нескольких десятков и они известны заранееПеречислите их константами прямо в тексте запроса
Список формируется пользователем или кодом, размер умеренныйПередайте массив или СписокЗначений через параметр
Набор значений нужно вычислить из данных базыИспользуйте вложенный запрос с одним полем и РАЗЛИЧНЫЕ
Список большой или используется в нескольких запросахПоместите таблицу значений во временную таблицу с индексом и примените соединение
Нужны элементы группы справочника со всеми подгруппамиИспользуйте В ИЕРАРХИИ с параметром-группой или списком групп

Проверка результата и отладка

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

Для отладки удобно временно вывести проверяемое поле и результат сравнения в выборку: добавьте в список полей выражение ВЫБОР КОГДА Поле В (&Список) ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК ПопадаетВОтбор и снимите условие из ГДЕ. Так видно, какие записи отсекаются и почему — особенно при проблемах с NULL и типами.

Консоль запросов (типовая из состава инструментов разработчика или внешняя обработка) позволяет заполнить параметры списками интерактивно и сразу видеть результат. Это быстрее, чем многократные запуски из кода, и снижает риск ошибиться в типах параметров.

Контрольные точки

Как проверить корректность отбора

Результат по одному известному значению
Норма

Запись найдена, поля заполнены ожидаемыми данными

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

Пустая выборка — проверяйте типы элементов списка и значение параметра

Количество записей при добавлении элементов в список
Норма

Выборка растёт на количество записей по новым значениям

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

Количество не меняется — часть значений не совпадает по типу или отсутствует в данных

Поля, участвующие в левых соединениях
Норма

NULL обработан через ЕСТЬNULL или исключён осознанно

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

Записи с NULL пропадают незаметно из результата

Время выполнения на рабочей базе
Норма

Запрос выполняется за приемлемое время при реальном размере списка

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

Резкий рост времени при увеличении списка — переходите на временную таблицу

Часто задаваемые вопросы

Можно ли передать в оператор В таблицу значений напрямую?

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

Чем В отличается от цепочки условий через ИЛИ?

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

Почему НЕ В возвращает пустой результат, хотя записи точно есть?

Почти наверняка в списке или во вложенном запросе присутствует значение NULL. При сравнении с NULL результат условия становится неопределённым, и записи отбрасываются. Добавьте во вложенный запрос отбор ГДЕ Поле ЕСТЬ НЕ NULL или замените конструкцию на ЛЕВОЕ СОЕДИНЕНИЕ с проверкой на NULL.

Работает ли В ИЕРАРХИИ в параметрах виртуальных таблиц?

Да, условие В ИЕРАРХИИ можно передавать в параметр отбора виртуальной таблицы через выражение с параметром, например задав условие в виде строки параметра «Номенклатура В ИЕРАРХИИ(&Группа)». Это позволяет отфильтровать данные ещё на этапе обращения к виртуальной таблице, что выгоднее по производительности, чем фильтрация результата.

Есть ли ограничение на количество элементов в списке для В?

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

Можно ли использовать В в секции ИМЕЮЩИЕ?

Да, оператор В допустим в ИМЕЮЩИЕ для фильтрации сгруппированных данных, например: ИМЕЮЩИЕ Контрагент В (&Список). Однако если условие не зависит от агрегатов, правильнее и быстрее написать его в ГДЕ — тогда лишние записи отсекаются до группировки, а не после неё.

Итог

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

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