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