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