Разработка и Конфигурация · 14 мин
Оператор В в запросах 1С: как фильтровать данные по списку значений
Как использовать оператор В в запросах 1С: фильтрация по списку значений, вложенные запросы, проверка иерархии, параметры и типичные ошибки с примерами кода.
Оператор В (IN) в языке запросов 1С проверяет, входит ли значение поля в заданный набор: список констант, результат вложенного запроса или таблицу значений, переданную через параметр. Это один из самых востребованных инструментов при отборе данных: он заменяет длинные цепочки условий через ИЛИ и позволяет строить гибкие отборы по произвольному количеству элементов.
Типичная задача выглядит так: нужно выбрать документы по нескольким контрагентам, товары из определённых групп номенклатуры или сотрудников конкретных подразделений. Вместо конструкции Контрагент = &К1 ИЛИ Контрагент = &К2 ИЛИ ... пишется одно условие Контрагент В (&СписокКонтрагентов), а список передаётся параметром из кода.
У оператора есть важные особенности: поведение с NULL-значениями, работа с иерархическими справочниками через В ИЕРАРХИИ, ограничения производительности при больших списках и нюансы типизации параметров. Ниже разобраны все основные сценарии с рабочими примерами.
Базовый синтаксис оператора В
Простейшая форма — перечисление значений прямо в тексте запроса через запятую в круглых скобках:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Товар,
Номенклатура.Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ВидНоменклатуры В (&Вид1, &Вид2, &Вид3)
Оператор возвращает ИСТИНУ, если значение поля совпадает хотя бы с одним элементом списка. Логически это эквивалентно цепочке равенств через ИЛИ, но запись короче и оптимизатор СУБД обычно обрабатывает её эффективнее.
Существует и обратная форма — НЕ В (NOT IN), которая отбирает записи, не входящие в список. С ней связана главная ловушка: если в списке или в проверяемом поле встречается NULL, результат может оказаться неожиданным (подробности — в разделе об ошибках).
Фильтрация по списку значений из параметра
На практике список значений почти всегда формируется динамически в коде модуля и передаётся в запрос параметром. Платформа позволяет передать массив, список значений или таблицу значений — все они корректно разворачиваются в условие В.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка КАК Документ,
| РеализацияТоваровУслуг.СуммаДокумента
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.Контрагент В (&СписокКонтрагентов)
| И РеализацияТоваровУслуг.Проведен";
СписокКонтрагентов = Новый СписокЗначений;
СписокКонтрагентов.Добавить(Контрагент1);
СписокКонтрагентов.Добавить(Контрагент2);
Запрос.УстановитьПараметр("СписокКонтрагентов", СписокКонтрагентов);
Результат = Запрос.Выполнить().Выгрузить();
Ключевое требование — тип элементов списка должен совпадать с типом поля. Если поле имеет составной тип (например, «Контрагент или Договор»), а в списке есть значения другого типа, платформа не выдаст ошибку, но сравнение по несовпадающим типам даст ЛОЖЬ, и данные «потеряются» молча. Это одна из самых коварных причин «пустого» результата запроса.
- 1Сформируйте в коде массив или СписокЗначений с элементами нужного типа
- 2Установите параметр: Запрос.УстановитьПараметр("Список", Массив)
- 3В тексте запроса напишите условие ГДЕ Поле В (&Список)
- 4Выполните запрос и проверьте, что количество записей соответствует ожиданию
- 5Если результат пуст — проверьте типы элементов списка и наличие данных в базе по одному известному значению
Оператор В с вложенным запросом
Вместо списка констант справа от оператора может стоять вложенный запрос в скобках. Это удобно, когда набор значений нужно получить из самой базы: например, выбрать всех контрагентов, у которых были продажи за период, или номенклатуру, входящую в определённую группу по дополнительному условию.
ВЫБРАТЬ
Заказы.Ссылка КАК Заказ,
Заказы.Контрагент
ИЗ
Документ.ЗаказКлиента КАК Заказы
ГДЕ
Заказы.Контрагент В
(ВЫБРАТЬ РАЗЛИЧНЫЕ
Продажи.Контрагент
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Продажи
ГДЕ
Продажи.СуммаОборот > 0)
Вложенный запрос должен возвращать ровно одно поле — иначе платформа выдаст ошибку при исполнении. Рекомендуется использовать РАЗЛИЧНЫЕ во вложенном запросе: дубликаты не влияют на результат, но увеличивают объём обрабатываемых данных.
По производительности конструкция с вложенным запросом часто уступает соединению таблиц (ЛЕВОЕ СОЕДИНЕНИЕ с проверкой на NULL или ВНУТРЕННЕЕ СОЕДИНЕНИЕ). Если запрос работает медленно на больших объёмах, перепишите условие В через соединение и сравните план выполнения.
Способы задать набор значений для оператора В
Подходит для фиксированных коротких списков, известных на этапе написания запроса. Не подходит для динамических отборов.
Основной вариант для отборов из кода и пользовательских настроек. Ограничение: при очень больших списках возможно падение производительности.
Когда набор вычисляется из данных базы. Требует ровно одного поля в выборке; на больших таблицах может уступать соединению.
Оптимально для больших списков: таблица помещается во временную, затем используется соединение. Требует больше кода, но работает быстрее.
Оператор В ИЕРАРХИИ для справочников
Отдельная разновидность — конструкция В ИЕРАРХИИ. Она проверяет, является ли элемент справочника подчинённым указанной группе (или элементу с иерархией) на любом уровне вложенности. Это стандартный способ отобрать товары целой группы вместе со всеми подгруппами.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Товар
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Ссылка В ИЕРАРХИИ (&ГруппаТоваров)
В параметр можно передать как одну группу, так и список групп — тогда в выборку попадут элементы всех указанных ветвей. Сама группа в результат не включается, если она не является элементом данных (для справочников с иерархией «группы и элементы» группы обычно не используются как значения полей документов).
Учтите: В ИЕРАРХИИ применяется только к ссылочным полям иерархических справочников и планов видов характеристик. Для неиерархических объектов и примитивных типов конструкция недоступна. Если поле составного типа и включает разные справочники, проверка иерархии выполняется только для той части значений, которая относится к иерархическому справочнику из параметра.
Проверка вхождения через временные таблицы
Когда список значений большой (тысячи элементов) или получен из другого запроса, эффективнее поместить его во временную таблицу и использовать соединение либо условие В с выборкой из временной таблицы. Менеджер временных таблиц позволяет передать таблицу значений прямо в запрос.
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| Таб.Контрагент
|ПОМЕСТИТЬ ВТ_Контрагенты
|ИЗ
| &ТаблицаКонтрагентов КАК Таб
|ИНДЕКСИРОВАТЬ ПО
| Контрагент
|;
|ВЫБРАТЬ
| Док.Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Док
|ГДЕ
| Док.Контрагент В (ВЫБРАТЬ Контрагент ИЗ ВТ_Контрагенты)";
Запрос.УстановитьПараметр("ТаблицаКонтрагентов", ТаблицаКонтрагентов);
Предложение ИНДЕКСИРОВАТЬ ПО ускоряет последующее соединение или проверку вхождения, особенно на больших временных таблицах. Это один из немногих способов явно влиять на производительность запросов в 1С, и пренебрегать им при больших объёмах не стоит.
Типичные ошибки и поведение с NULL
Самая частая проблема — пустой результат из-за несовпадения типов. Например, в параметр передали массив строк, а поле имеет тип «СправочникСсылка». Запрос выполнится без ошибок, но ничего не найдёт. Всегда проверяйте типы элементов списка перед выполнением.
Вторая ловушка — NULL. Если проверяемое поле содержит NULL (например, из-за левого соединения), то условие Поле В (&Список) даст NULL, а не ИСТИНА, и запись не попадёт в результат. С конструкцией НЕ В ситуация ещё тоньше: если сам список содержит NULL (что возможно при вложенном запросе), результат условия становится неопределённым, и отбор может вернуть пустую выборку там, где ожидались данные.
Защитные приёмы: используйте ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) перед сравнением, а во вложенных запросах для НЕ В отфильтровывайте NULL условием ГДЕ Поле ЕСТЬ НЕ NULL. Либо замените НЕ В на конструкцию ЛЕВОЕ СОЕДИНЕНИЕ с проверкой ГДЕ Таблица.Поле ЕСТЬ NULL — она предсказуемее.
Производительность и ограничения
При небольшом числе элементов (единицы — десятки значений) оператор В с параметром работает быстро и не требует оптимизации. Проблемы начинаются на списках из тысяч значений: запрос компилируется в длинное условие, и время подготовки и выполнения заметно растёт. Признак проблемы — запрос, который на тестовых данных выполнялся мгновенно, «зависает» в рабочей базе.
Признак того, что пора переходить на временную таблицу: список формируется программно, содержит сотни и более элементов или используется в нескольких запросах пакета. Временная таблица с индексом и соединение почти всегда выигрывают у гигантского условия В.
Ещё одно ограничение: в условии В нельзя использовать агрегатные функции без группировки, а само условие в секции ГДЕ не должно содержать вложенных запросов с агрегацией по соединяемым данным без крайней необходимости — это усложняет оптимизацию. Если логика становится громоздкой, разбейте запрос на пакет из нескольких с временными таблицами.
Как выбрать реализацию отбора
Проверка результата и отладка
Перед тем как встраивать условие В в рабочий отчёт, проверьте его на контрольном примере. Возьмите одно заведомо существующее значение, передайте его в списке из одного элемента и убедитесь, что запись находится. Затем добавьте второе значение и проверьте, что выборка выросла ровно на ожидаемые записи.
Для отладки удобно временно вывести проверяемое поле и результат сравнения в выборку: добавьте в список полей выражение ВЫБОР КОГДА Поле В (&Список) ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК ПопадаетВОтбор и снимите условие из ГДЕ. Так видно, какие записи отсекаются и почему — особенно при проблемах с NULL и типами.
Консоль запросов (типовая из состава инструментов разработчика или внешняя обработка) позволяет заполнить параметры списками интерактивно и сразу видеть результат. Это быстрее, чем многократные запуски из кода, и снижает риск ошибиться в типах параметров.
Как проверить корректность отбора
Запись найдена, поля заполнены ожидаемыми данными
Пустая выборка — проверяйте типы элементов списка и значение параметра
Выборка растёт на количество записей по новым значениям
Количество не меняется — часть значений не совпадает по типу или отсутствует в данных
NULL обработан через ЕСТЬNULL или исключён осознанно
Записи с NULL пропадают незаметно из результата
Запрос выполняется за приемлемое время при реальном размере списка
Резкий рост времени при увеличении списка — переходите на временную таблицу
Часто задаваемые вопросы
Можно ли передать в оператор В таблицу значений напрямую?
Да, таблицу значений можно передать параметром, но использовать её напрямую в условии В нельзя — её нужно сначала поместить во временную таблицу через конструкцию ПОМЕСТИТЬ, а затем применять вложенный запрос к этой временной таблице или соединение с ней. Потребуется установить МенеджерВременныхТаблиц у объекта запроса.
Чем В отличается от цепочки условий через ИЛИ?
Логически они эквивалентны для конечного списка значений. Отличия практические: запись с В короче, легче передаётся параметром переменной длины и обычно лучше обрабатывается оптимизатором. Цепочку ИЛИ приходится генерировать программно при динамическом числе значений, что усложняет код и замедляет компиляцию запроса.
Почему НЕ В возвращает пустой результат, хотя записи точно есть?
Почти наверняка в списке или во вложенном запросе присутствует значение NULL. При сравнении с NULL результат условия становится неопределённым, и записи отбрасываются. Добавьте во вложенный запрос отбор ГДЕ Поле ЕСТЬ НЕ NULL или замените конструкцию на ЛЕВОЕ СОЕДИНЕНИЕ с проверкой на NULL.
Работает ли В ИЕРАРХИИ в параметрах виртуальных таблиц?
Да, условие В ИЕРАРХИИ можно передавать в параметр отбора виртуальной таблицы через выражение с параметром, например задав условие в виде строки параметра «Номенклатура В ИЕРАРХИИ(&Группа)». Это позволяет отфильтровать данные ещё на этапе обращения к виртуальной таблице, что выгоднее по производительности, чем фильтрация результата.
Есть ли ограничение на количество элементов в списке для В?
Жёсткого документированного предела нет, но на практике при списках из тысяч элементов заметно растут время компиляции и выполнения запроса. Ориентир простой: десятки значений — без опасений, сотни и тысячи — переносите данные во временную таблицу с индексом и используйте соединение.
Можно ли использовать В в секции ИМЕЮЩИЕ?
Да, оператор В допустим в ИМЕЮЩИЕ для фильтрации сгруппированных данных, например: ИМЕЮЩИЕ Контрагент В (&Список). Однако если условие не зависит от агрегатов, правильнее и быстрее написать его в ГДЕ — тогда лишние записи отсекаются до группировки, а не после неё.
Что важно запомнить
Оператор В проверяет вхождение значения в список: константы, параметр (массив, список значений) или вложенный запрос с одним полем. Для групп справочников используйте В ИЕРАРХИИ. Следите за типами элементов и NULL — это главные причины «пустых» результатов. На больших списках переходите на временные таблицы с индексом и соединение.