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