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