Передаём коллекцию значений в запрос 1С: условие В, таблицы значений и СКД
Содержание
Массив передают в запрос 1С как обычный параметр: Запрос.УстановитьПараметр("Список", МассивСсылок), а в тексте запроса используют условие ГДЕ Поле В (&Список). Платформа 8.3 сама разворачивает коллекцию в перечень значений, цикл и склейка строк не нужны.
Тот же приём работает со СписокЗначений и ФиксированныйМассив. Массив структур или объектов так передать нельзя: его превращают в таблицу значений или в массив ссылок. Ниже синтаксис, ограничения, рабочие примеры и то, как поступать со списками на тысячи элементов.
Как массив попадает в запрос: что принимает параметр
Параметр запроса принимает значение любого типа, который можно хранить в базе: ссылку, число, строку, дату, булево. Если в параметр положить коллекцию, платформа считает её набором таких значений и подставляет в условие целиком.
Какие коллекции подходят:
- ✅
Массив— основной вариант, элементы могут быть разных типов; - ✅
ФиксированныйМассив— то же самое, удобно, когда массив пришёл с клиента через реквизит формы; - ✅
СписокЗначений— в запрос уходят только значения, представления и пометки игнорируются; - ✅
ТаблицаЗначений— но не в условиеВ, а как источник данныхИЗ &Таблица(о нём ниже); - ❌ массив структур, соответствие, массив
ДокументОбъектилиСправочникОбъект— запрос их не понимает.
Запрос выполняется только на сервере. Если массив собран на клиенте (например, выделенные строки списка), передайте его в серверную процедуру формы с директивой &НаСервере или в общий модуль. Массив ссылок сериализуется без проблем.
Дубликаты в массиве не мешают: условие В проверяет вхождение, а не количество совпадений. Чистить массив от повторов перед передачей не обязательно.
Синтаксис условия В (&Параметр) с массивом
Минимальный рабочий пример — выбрать контрагентов по списку ИНН:
МассивИНН = Новый Массив;
МассивИНН.Добавить("7701234567");
МассивИНН.Добавить("7809876543");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Контрагент,
| Контрагенты.ИНН КАК ИНН
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.ИНН В (&СписокИНН)";
Запрос.УстановитьПараметр("СписокИНН", МассивИНН);
Выборка = Запрос.Выполнить().Выбрать();
Что здесь обязательно:
- Скобки вокруг параметра:
В (&СписокИНН). Без них конструктор и платформа выдадут синтаксическую ошибку. - Имя параметра в тексте и в
УстановитьПараметрсовпадает посимвольно, регистр не важен. - Тип элементов массива совпадает с типом поля. Строка «7701234567» не найдёт ссылку на контрагента, а число 7701234567 не найдёт строковый ИНН.
Отрицание и иерархия
Для обратного отбора пишут ГДЕ НЕ Поле В (&Список). Для справочников с группами есть В ИЕРАРХИИ:
"ГДЕ Товары.Номенклатура В ИЕРАРХИИ (&ГруппыНоменклатуры)"
Такое условие отберёт и сами элементы массива, и всё, что лежит внутри переданных групп на любом уровне вложенности.
Пустой массив
Если массив пуст, условие В (&Список) ложно для всех строк, и запрос вернёт пустой результат. Ошибки не будет. Частая логика «пустой список — значит, без отбора» делается явно:
"ГДЕ (&БезОтбора ИЛИ Товары.Номенклатура В (&Список))"
...
Запрос.УстановитьПараметр("БезОтбора", Список.Количество() = 0);
Запрос.УстановитьПараметр("Список", Список);
Ограничения и типичные ошибки при передаче массива
Большинство проблем с массивами в запросах сводятся к типам и к тому, что именно положили в параметр. Сводка по симптомам:
Ещё несколько ограничений, о которых лучше знать заранее:
- 🔸 Только одно поле слева. Конструкция
(Поле1, Поле2) В (...)работает с вложенным запросом, но не с массивом. Для пар значений нужна таблица значений. - 🔸 Массив массивов не разворачивается. Вложенный массив параметр не примет, предварительно соберите плоский список.
- 🔸 Составной тип поля. Если поле может хранить ссылки разных типов, в массиве тоже могут быть разные типы — это корректно, отбор сработает по каждому.
- 🔸 Ссылки из другой базы. Ссылка, полученная по
ПолучитьСсылку()с чужим УИД, формально валидна, но строк в выборке не даст.
Массив структур и массив объектов: как подготовить данные
Типовая ситуация: из внешнего файла или веб-сервиса пришёл массив структур вида Новый Структура("Номенклатура, Количество", ...). В условие В его не подставить. Есть два пути.
Путь 1: нужны только ссылки
Выберите из структур одно поле в отдельный массив:
Ссылки = Новый Массив;
Для Каждого Элемент Из МассивСтруктур Цикл
Ссылки.Добавить(Элемент.Номенклатура);
КонецЦикла;
Запрос.УстановитьПараметр("Номенклатура", Ссылки);
Для массива объектов (ДокументОбъект, СправочникОбъект) то же самое делают со свойством Ссылка. Если исходные данные уже лежат в таблице значений, нужный массив возвращает Таблица.ВыгрузитьКолонку("Номенклатура").
Путь 2: нужны все поля — таблица значений во временной таблице
Когда в запросе требуются и ссылка, и количество, и цена, массив структур переносят в ТаблицаЗначений. Колонкам обязательно задайте типы, иначе платформа не сможет поместить таблицу во временную.
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Номенклатура",
Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
Таблица.Колонки.Добавить("Количество",
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
Для Каждого Элемент Из МассивСтруктур Цикл
ЗаполнитьЗначенияСвойств(Таблица.Добавить(), Элемент);
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Данные.Номенклатура КАК Номенклатура,
| Данные.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ
| &Таблица КАК Данные
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Данные.Номенклатура,
| ВТ_Данные.Количество,
| ВТ_Данные.Номенклатура.Артикул КАК Артикул
|ИЗ
| ВТ_Данные КАК ВТ_Данные";
Запрос.УстановитьПараметр("Таблица", Таблица);
Таблица значений в ИЗ &Таблица допустима только в запросе, который помещает результат во временную таблицу. Сразу соединять её с регистрами в одном запросе нельзя — сначала ПОМЕСТИТЬ, потом работа с временной таблицей.
Имена колонок в таблице должны совпадать с ключами структуры, иначе ЗаполнитьЗначенияСвойств молча пропустит поле, и в запрос уйдут пустые значения.
Оптимизация запросов с массивом в параметре
Для списка из десятков или сотен ссылок В (&Массив) работает быстро, особенно если поле индексировано: ссылки, реквизиты с флажком индексирования, измерения регистров.
Когда элементов становятся тысячи, SQL-текст разрастается, а СУБД хуже подбирает план. В таких случаях выручает временная таблица с индексом:
"ВЫБРАТЬ
| Список.Номенклатура КАК Номенклатура
|ПОМЕСТИТЬ ВТ_Отбор
|ИЗ
| &ТаблицаОтбора КАК Список
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;
|ВЫБРАТЬ
| Остатки.Номенклатура,
| Остатки.КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(
| ,
| Номенклатура В (ВЫБРАТЬ ВТ_Отбор.Номенклатура ИЗ ВТ_Отбор КАК ВТ_Отбор)
| ) КАК Остатки"
Таблицу отбора с одной колонкой проще всего получить так: создать ТаблицаЗначений с типизированной колонкой и заполнить её ЗагрузитьКолонку(Массив, "Номенклатура").
Что выбрать в зависимости от ситуации:
| Способ | Когда подходит | Минусы |
|---|---|---|
В (&Массив) | До сотен значений, простой отбор | На больших списках растёт текст SQL |
В (&Массив) в параметрах виртуальной таблицы | Остатки и обороты регистров по списку | Те же, что выше |
Временная таблица + ИНДЕКСИРОВАТЬ ПО | Тысячи значений, соединения с несколькими таблицами | Больше кода, нужен типизированный источник |
| Вложенный запрос вместо массива | Список можно получить запросом из базы | Не подходит для данных извне |
Ещё два практических приёма:
- 💡 Если массив сам получен запросом, не выгружайте его в память — оставьте результат во временной таблице через
МенеджерВременныхТаблици сошлитесь на неё в следующем запросе. - 💡 Отбор по массиву для виртуальных таблиц
ОстаткииОборотыставьте в параметры таблицы, а не вГДЕ. Так СУБД режет данные до агрегации.
Пример: отбор реализаций по массиву номенклатуры в БП 3.0
Задача: найти проведённые документы «Реализация (акты, накладные, УПД)» за период, в которых есть хотя бы одна позиция из переданного списка товаров. Табличная часть документа в БП 3.0 называется Товары.
&НаСервере
Функция ДокументыПоНоменклатуре(МассивНоменклатуры, НачалоПериода, КонецПериода)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Товары.Ссылка КАК Документ,
| Товары.Ссылка.Дата КАК Дата,
| Товары.Ссылка.Контрагент КАК Контрагент
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
| Товары.Номенклатура В (&Номенклатура)
| И Товары.Ссылка.Дата МЕЖДУ &Начало И &Конец
| И Товары.Ссылка.Проведен
|
|УПОРЯДОЧИТЬ ПО
| Дата";
Запрос.УстановитьПараметр("Номенклатура", МассивНоменклатуры);
Запрос.УстановитьПараметр("Начало", НачалоДня(НачалоПериода));
Запрос.УстановитьПараметр("Конец", КонецДня(КонецПериода));
Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Документ");
КонецФункции
Разбор решений в этом примере:
ВЫБРАТЬ РАЗЛИЧНЫЕнужен, потому что документ с тремя подходящими строками иначе попадёт в выборку трижды.НачалоДняиКонецДнязащищают от потери документов последнего дня: дата без времени означает полночь.- Функция возвращает массив ссылок, который можно сразу передать в следующий запрос тем же способом.
Если в списке есть группы номенклатуры, замените В (&Номенклатура) на В ИЕРАРХИИ (&Номенклатура), и в выборку попадут товары из этих групп.
Массив в параметрах отчёта на СКД
В системе компоновки данных параметр-список настраивается в самой схеме. Откройте схему в Конфигураторе, перейдите на вкладку «Параметры» и у нужного параметра установите флажок «Доступен список значений». В тексте запроса набора данных используется та же конструкция В (&Номенклатура).
Из кода значение задают через параметры данных компоновщика. Надёжнее передавать СписокЗначений:
Список = Новый СписокЗначений;
Список.ЗагрузитьЗначения(МассивНоменклатуры);
Параметр = Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных
.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Номенклатура"));
Если Параметр <> Неопределено Тогда
Параметр.Значение = Список;
Параметр.Использование = Истина;
КонецЕсли;
Альтернатива параметру — отбор компоновки с видом сравнения «В списке». Пользователь видит его в настройках отчёта и может поправить сам. Отличие в том, где срабатывает условие:
| Подход | Где работает условие | Когда выбирать |
|---|---|---|
| Параметр со списком значений | Прямо в тексте запроса набора | Список обязателен для логики отчёта, нужен в параметрах виртуальных таблиц |
| Отбор «В списке» | Компоновка добавляет условие сама | Отбор пользовательский, его можно снять или изменить |
Параметр-список без значения работает как пустой массив: отчёт ничего не покажет. Если отбор по нему необязателен, заключите условие в тексте запроса набора в фигурные скобки {} — тогда при снятом флажке использования параметра СКД просто уберёт этот фрагмент из запроса.