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

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

Массив как параметр запроса в 1С: передача списка значений

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

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

Механизм прост: вы создаёте запрос с условием вида ГДЕ Ссылка В (&СписокСсылок), затем методом УстановитьПараметр передаёте в него объект типа «Массив» или «СписокЗначений». Платформа сама разворачивает коллекцию в набор значений на стороне СУБД. Это работает и в клиент-серверном, и в файловом варианте, и в тонком, и в толстом клиенте.

Ниже разобраны синтаксис, варианты применения, ограничения по типам и размеру, а также ошибки, которые чаще всего приводят к пустому результату или падению производительности.

Базовый синтаксис: как передать массив в запрос

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

МассивТоваров = Новый Массив;

МассивТоваров.Добавить(СсылкаТовар1);

МассивТоваров.Добавить(СсылкаТовар2);

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

| Номенклатура.Ссылка В (&МассивТоваров)";

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

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

Ключевые моменты: имя параметра в тексте запроса начинается с амперсанда &, а в методе УстановитьПараметр указывается без него. Порядок вызовов не критичен — параметр можно установить как до, так и после присвоения текста запроса, главное — до выполнения.

Оператор В проверяет вхождение значения поля в переданный набор. Для обратного отбора используется НЕ В (&МассивТоваров) — так можно исключить из выборки нежелательные элементы, например помеченные на удаление документы определённого списка.

Что можно передать вместо массива

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

Список значений — удобен, когда данные берутся из элемента формы «СписокЗначений» или когда нужны представления элементов параллельно со значениями. Передаётся точно так же: Запрос.УстановитьПараметр("Список", СписокЗначений).

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

Фиксированный массив тоже принимается — например, колонка таблицы значений, выгруженная методом ВыгрузитьКолонку, возвращает именно массив, поэтому дополнительных преобразований не требуется.

Сравнение вариантов передачи списка

Массив + оператор В

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

Временная таблица через МенеджерВременныхТаблиц

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

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

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

Отбор по массиву ссылок на документы и справочники

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

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

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

"ВЫБРАТЬ

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

| РеализацияТовары.Номенклатура КАК Номенклатура,

| РеализацияТовары.Количество КАК Количество

|ИЗ

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

|ГДЕ

| РеализацияТовары.Ссылка В (&СписокДокументов)";

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

ТаблицаТоваров = Запрос.Выполнить().Выгрузить();

Обратите внимание: сравниваться должны значения одинакового типа. Если в массиве лежат ссылки на документ «РеализацияТоваровУслуг», а поле запроса — составного типа (например, «ДокументОснование» с несколькими типами), условие всё равно отработает, но при смешении несовместимых типов в одном массиве возможна ошибка исполнения запроса. Перед передачей массив стоит очищать от значений Неопределено и пустых ссылок, если они не нужны в отборе.

Если массив пуст, условие В (&Параметр) вернёт пустую выборку — это корректное поведение, а не ошибка. Если пустой массив должен означать «без отбора», добавьте проверку в коде и формируйте текст запроса без условия, либо используйте конструкцию ГДЕ (&ОтборПоСписку = ЛОЖЬ ИЛИ Ссылка В (&Список)) с дополнительным флагом.

Массивы при работе с временными таблицами

Когда список большой или используется в нескольких запросах пакета, эффективнее поместить его во временную таблицу. Для этого массив сначала превращают в таблицу значений с одной колонкой, затем передают параметром в запрос с конструкцией ПОМЕСТИТЬ:

ТаблицаСсылок = Новый ТаблицаЗначений;

ТаблицаСсылок.Колонки.Добавить("Ссылка",

Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

Для Каждого Элемент Из МассивТоваров Цикл

ТаблицаСсылок.Добавить().Ссылка = Элемент;

КонецЦикла;

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

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

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

"ВЫБРАТЬ

| Таб.Ссылка КАК Ссылка

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

|ИЗ

| &ТаблицаСсылок КАК Таб

|;

|ВЫБРАТЬ

| Остатки.Номенклатура КАК Номенклатура,

| Остатки.КоличествоОстаток КАК Остаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(

| ,

| Номенклатура В (ВЫБРАТЬ ВТ_Товары.Ссылка ИЗ ВТ_Товары)) КАК Остатки";

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

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

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

Порядок действий для большого списка
  1. 1
    Сформируйте массив ссылок и уберите дубли и пустые значения
  2. 2
    Преобразуйте массив в таблицу значений с типизированной колонкой
  3. 3
    Создайте МенеджерВременныхТаблиц и поместите таблицу во временную таблицу запроса
  4. 4
    Добавьте ИНДЕКСИРОВАТЬ ПО по полю соединения
  5. 5
    Используйте временную таблицу в соединении или вложенном запросе основной выборки
  6. 6
    Выполните запрос и проверьте число строк результата

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

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

У разных СУБД есть практические ограничения на число элементов в конструкции IN. На MS SQL при очень длинных списках растёт время компиляции запроса, на PostgreSQL деградирует план выполнения. Точные пороги зависят от версии СУБД и настроек, поэтому надёжное практическое правило: если элементов больше нескольких тысяч, переходите на временную таблицу.

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

Третий момент — индексы. Условие Поле В (&Массив) эффективно использует индекс по полю, если он есть. По реквизитам, не входящим в индексы, выборка по большому списку превратится в полное сканирование таблицы. Для часто используемых отборов проверьте индексацию реквизита в конфигураторе (свойство «Индексировать»).

Типичные ошибки и их диагностика

Первая группа ошибок — пустой результат при корректном с виду коде. Причины обычно такие: в массиве лежат значения не того типа (например, строки с кодами вместо ссылок), массив не заполнен из-за логики выше по коду, либо сравниваются разные представления — ссылка с кодом. Диагностируется выводом Массив.Количество() и типа первого элемента перед выполнением запроса.

Вторая группа — ошибки исполнения. Сообщение вида «Несовместимые типы» возникает, когда в одном массиве смешаны значения разных типов, которые СУБД не может привести к общему. Лечится фильтрацией массива перед передачей или явным указанием типа через ВЫРАЗИТЬ в тексте запроса.

Третья частая ситуация — параметр установлен, но в тексте запроса имя указано с опечаткой или без амперсанда. Платформа в этом случае либо сообщит о неизвестном параметре, либо молча вернёт не то, что ожидалось. Проверяйте соответствие имён символ в символ.

Типичные ошибки
01
Подстановка массива в текст запроса через строковую конкатенацию — теряется типизация и появляется риск ошибок СУБД
02
Передача массива с дублями и значениями Неопределено — раздувает список параметров и может давать неожиданные строки
03
Использование оператора В с массивом из десятков тысяч элементов вместо временной таблицы — таймауты и ошибки СУБД
04
Сравнение поля составного типа с массивом без учёта типов — ошибка несовместимости или пустая выборка
05
Ожидание, что пустой массив отключит отбор — на самом деле условие В вернёт пустой результат

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

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

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

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

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

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

Совпадает с ожидаемым списком, нет Неопределено

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

Массив пуст или содержит значения неожиданного типа

Тип значений массива
Норма

Все элементы одного типа, совместимого с полем отбора

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

Смешанные типы, строки вместо ссылок

Содержимое результата
Норма

Все значения ключевого поля входят в исходный массив

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

Появились лишние строки или пропали ожидаемые

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

Запрос отрабатывает быстро даже на полном списке

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

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

FAQ

Можно ли передать в запрос массив структур?

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

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

Условие В (&Параметр) с пустой коллекцией вернёт пустую выборку — запрос выполнится без ошибки, но строк не будет. Если пустой список должен означать «отбор не применяется», добавьте в код проверку Количество() = 0 и формируйте текст запроса без этого условия или используйте дополнительный параметр-флаг.

Чем массив отличается от списка значений при передаче в запрос?

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

Как передать массив в параметры виртуальной таблицы регистра?

Точно так же — через УстановитьПараметр, а в тексте запроса условие указывается в скобках виртуальной таблицы: РегистрНакопления.Товары.Остатки(, Номенклатура В (&Список)). Отбор в параметрах виртуальной таблицы эффективнее, чем в секции ГДЕ, потому что применяется до формирования выборки.

Когда обязательно нужна временная таблица вместо массива?

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

Работает ли передача массива в запросе на управляемых формах и в веб-клиенте?

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

Итог

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

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