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

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

Массив в запрос 1С 8.3 как параметр: передача и практические приёмы

Как передать массив в запрос 1С 8.3 через УстановитьПараметр, использовать В (&Список), В ИЕРАРХИИ, временные таблицы. Примеры кода, ошибки и ограничения.

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

Механизм прост: массив (или список значений) присваивается параметру запроса через метод УстановитьПараметр(), а в тексте запроса параметр используется с оператором В (...). Запрос автоматически раскрывает коллекцию в набор значений и выполняет сравнение по каждому элементу. Это работает и в клиент-серверном, и в файловом режиме, и в динамических списках, и в СКД.

Ниже разобраны синтаксис передачи, особенности операторов В и В ИЕРАРХИИ, работа с пустыми массивами, альтернатива через временные таблицы и типичные ошибки, из-за которых запрос возвращает неожиданный результат или падает с ошибкой.

Как передать массив параметром в запрос

Базовый приём состоит из трёх шагов: сформировать массив, установить его как параметр, использовать параметр в условии В. Никаких преобразований типов делать не нужно — платформа сама сопоставит элементы массива с типом сравниваемого поля.

МассивНоменклатуры = Новый Массив;

МассивНоменклатуры.Добавить(Справочники.Номенклатура.НайтиПоКоду("000000001"));

МассивНоменклатуры.Добавить(Справочники.Номенклатура.НайтиПоКоду("000000002"));

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

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

"ВЫБРАТЬ

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

| СУММА(Товары.КоличествоОстаток) КАК Остаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура В (&Список)) КАК Товары

|СГРУППИРОВАТЬ ПО

| Товары.Номенклатура";

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

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

Обратите внимание на параметр виртуальной таблицы: условие Номенклатура В (&Список) вынесено в параметры виртуальной таблицы Остатки(), а не в секцию ГДЕ. Это важно для производительности — отбор применяется на уровне СУБД до выборки остатков, а не после.

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

Отбор по группам: оператор В ИЕРАРХИИ

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

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

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

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

Запрос.УстановитьПараметр("Группы", МассивГрупп);

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

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

Работа с пустым массивом и типизация

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

Две практические защиты. Первая — проверять заполненность массива до выполнения и либо не выполнять запрос вовсе, либо подменять условие. Вторая — если пустой массив должен означать «без отбора», формировать текст запроса динамически:

Если МассивНоменклатуры.Количество() = 0 Тогда

ТекстУсловия = "ИСТИНА";

Иначе

ТекстУсловия = "Номенклатура В (&Список)";

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

КонецЕсли;

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

Типичные ошибки
01
Передача пустого массива без проверки — запрос возвращает пустой результат или падает с ошибкой типов в параметрах виртуальной таблицы
02
Передача таблицы значений вместо массива в оператор В — ошибка выполнения; нужно выгрузить колонку методом ВыгрузитьКолонку()
03
Условие В (&Список) в секции ГДЕ вместо параметров виртуальной таблицы — отбор применяется после выборки, запрос работает медленнее
04
Склейка значений массива в строку запроса вместо параметра — риск ошибок на спецсимволах, потери типа и SQL-инъекций в прямых запросах
05
Дубли значений в массиве большого размера — лишняя нагрузка на СУБД; перед передачей стоит свернуть массив через соответствие

Массив в СКД и динамических списках

В системе компоновки данных массив передаётся через параметр данных компоновки. Тип параметра в наборе данных должен допускать список значений: в схеме компоновки у параметра устанавливается флаг «Доступен список значений». Тогда в отборе можно использовать вид сравнения «В списке» или «В группе из списка» (аналог В ИЕРАРХИИ).

ПараметрСКД = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("СписокНоменклатуры");

ПараметрСКД.Значение = МассивНоменклатуры;

ПараметрСКД.Использование = Истина;

Для динамических списков массив устанавливается через Список.Параметры.УстановитьЗначениеПараметра("Имя", Массив). Требование то же: параметр должен быть объявлен в тексте запроса динамического списка и допускать список значений.

В СКД есть дополнительный плюс: отбор «В списке» может накладываться на уровне настроек без изменения текста запроса, и платформа сама передаст коллекцию в запрос. Это удобно, когда список формирует пользователь в отборе отчёта.

Когда массива недостаточно: временные таблицы

Оператор В сравнивает одно поле с набором значений. Если нужно передать в запрос набор строк с несколькими полями — например, пары «номенклатура + характеристика» с количеством — массив не подходит. Решение — временная таблица, которую запрос помещает в менеджер временных таблиц, а следующий запрос соединяет с ней.

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

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

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

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

"ВЫБРАТЬ

| ТЗ.Номенклатура КАК Номенклатура,

| ТЗ.Количество КАК Количество

|ПОМЕСТИТЬ ВТ_Товары

|ИЗ

| &ТЗ КАК ТЗ";

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

Запрос.Выполнить();

Здесь таблица значений передаётся параметром &ТЗ — это единственный случай, когда таблицу значений можно передать в запрос напрямую. Дальше временная таблица ВТ_Товары доступна всем запросам с тем же менеджером временных таблиц до его закрытия.

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

Сравнение способов передачи списка значений

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

Массив через УстановитьПараметр + В (&Список)

Стандартный способ для отбора по одному полю. Простой и быстрый. Ограничение: сравнение только одного поля, пустой массив требует отдельной обработки.

Список значений

Работает так же, как массив. Удобен, когда данные уже лежат в списке значений (отборы, элементы формы). Лишнего преобразования не требуется.

Временная таблица

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

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

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

Склейка в строку запроса

Не рекомендуется: потеря типов, ошибки на спецсимволах, невозможность повторного использования текста запроса. Допустима только для служебных разовых сценариев.

Выбор сводится к простому правилу: одно поле и значения из кода — массив; несколько полей или повторное использование — временная таблица; значения уже в базе — вложенный запрос. Склейку строк в текст запроса стоит исключить из практики полностью.

Проверка результата и ограничения

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

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

По производительности: передача массива из десятков и сотен элементов работает без проблем. При массивах в десятки тысяч элементов запрос может выполняться медленнее из-за объёма передаваемых данных и плана запроса на СУБД — в таких случаях временная таблица с индексированием (ИНДЕКСИРОВАТЬ ПО) обычно даёт более предсказуемый результат.

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

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

Заполненность результата
Норма

Строки возвращаются, значения поля входят в переданный массив

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

Пустой результат при гарантированно существующих данных — проверить типы и имя параметра

Типы элементов массива
Норма

Все элементы имеют тип сравниваемого поля (ссылка нужного вида)

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

В массиве строки, числа или NULL вместо ссылок — сравнение молча не срабатывает

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

Условие В (&Список) стоит в параметрах виртуальной таблицы

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

Условие в секции ГДЕ поверх виртуальной таблицы — лишнее сканирование

Освобождение ресурсов
Норма

МенеджерВременныхТаблиц закрыт после пакета запросов

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

Менеджер не закрыт — временные таблицы висят в памяти сеанса

Порядок действий при внедрении

Порядок действий
  1. 1
    Сформируйте массив и убедитесь, что все элементы имеют тип сравниваемого поля
  2. 2
    Удалите дубли, если массив собран из нескольких источников
  3. 3
    Проверьте Количество() = 0 и определите поведение для пустого списка
  4. 4
    Напишите текст запроса с условием Поле В (&ИмяПараметра), для виртуальных таблиц — в их параметрах
  5. 5
    Вызовите Запрос.УстановитьПараметр до Выполнить()
  6. 6
    Выполните запрос и проверьте, что результат содержит только значения из массива
  7. 7
    Если нужен набор с несколькими полями — перейдите на временную таблицу через МенеджерВременныхТаблиц

Частые вопросы

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

Нет, оператор В принимает массив, список значений, вложенный запрос или временную таблицу. Таблицу значений нужно либо преобразовать в массив методом ВыгрузитьКолонку("ИмяКолонки"), либо поместить целиком во временную таблицу через параметр &ТЗ и дальше соединять её с основной выборкой.

Что произойдёт, если передать пустой массив?

Условие В (&Список) не выполнится ни для одной строки — результат будет пустым. В параметрах виртуальных таблиц и в СКД пустой нетипизированный список может дополнительно вызвать ошибку несоответствия типов. Правильное решение — проверять Количество() до выполнения и либо пропускать запрос, либо убирать условие из текста.

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

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

Работает ли передача массива в динамическом списке и СКД?

Да. В динамическом списке массив устанавливается через Список.Параметры.УстановитьЗначениеПараметра, в СКД — через параметр данных компоновки с включённым флагом использования. В обоих случаях параметр в схеме должен допускать список значений, а в отборе СКД доступны виды сравнения «В списке» и «В группе из списка».

Есть ли ограничение на размер массива?

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

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

Чаще всего причины три: типы элементов массива не совпадают с типом поля (например, строки вместо ссылок), параметр установлен после Выполнить() или имя параметра в коде не совпадает с именем в тексте запроса. Реже — в массив попали значения NULL, которые не равны ничему, включая другой NULL.

Итог

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

Массив передаётся в запрос 1С 8.3 штатно: УстановитьПараметр плюс оператор В (&Имя), для групп — В ИЕРАРХИИ. Проверяйте типы элементов и пустоту массива, выносите условие в параметры виртуальных таблиц, а для наборов с несколькими полями используйте временные таблицы. Склейку значений в текст запроса не применяйте.