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

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

Как добавить массив в запрос 1С

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

Массив в запросе 1С используется всякий раз, когда нужно отфильтровать данные по списку значений: выбрать документы по нескольким контрагентам, товары по группе номенклатуры, проводки по набору счетов. Встроенный язык запросов не поддерживает перебор коллекций напрямую, поэтому массив передаётся в запрос как параметр, а в тексте запроса применяется оператор В или В ИЕРАРХИИ.

Механизм прост: вы создаёте массив программно, заполняете его ссылками, примитивными значениями или перечислениями, устанавливаете его через метод УстановитьПараметр() и ссылаетесь на него в тексте запроса по имени с амперсандом. Запрос на уровне СУБД преобразует такой параметр в список значений условия IN.

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

Базовый способ: массив как параметр и оператор В

Стандартный сценарий выглядит так. Создаётся массив, заполняется ссылками или значениями, затем передаётся в запрос одноимённым параметром. В тексте запроса условие записывается как ГДЕ Таблица.Поле В (&Параметр).

МассивКонтрагентов = Новый Массив;

МассивКонтрагентов.Добавить(Контрагент1);

МассивКонтрагентов.Добавить(Контрагент2);

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

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

"ВЫБРАТЬ

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

| Реализация.СуммаДокумента КАК Сумма

|ИЗ

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

|ГДЕ

| Реализация.Контрагент В (&Контрагенты)

| И Реализация.Проведен";

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

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

Имя параметра в УстановитьПараметр() указывается без амперсанда, а в тексте запроса — с амперсандом. Это частая причина ошибки «Параметр не найден»: имена должны совпадать посимвольно, включая регистр не важен, но лишние пробелы и опечатки критичны.

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

Порядок действий
  1. 1
    Создайте массив через Новый Массив и заполните значениями одного типа
  2. 2
    Напишите текст запроса с условием ГДЕ Поле В (&ИмяПараметра)
  3. 3
    Передайте массив: Запрос.УстановитьПараметр("ИмяПараметра", Массив)
  4. 4
    Выполните запрос и проверьте выборку на ожидаемое количество строк
  5. 5
    Если выборка пуста — проверьте типы элементов массива и имя параметра

Отбор по иерархии с помощью В ИЕРАРХИИ

Если в массиве лежат группы справочника, а нужны все элементы внутри этих групп, простое В не подойдёт — оно сравнивает на точное равенство. Для иерархических справочников используется оператор В ИЕРАРХИИ:

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

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

| Номенклатура.Ссылка В ИЕРАРХИИ (&Группы)";

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

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

Учтите, что В ИЕРАРХИИ применимо только к полям ссылочного типа на иерархический справочник или план видов характеристик. Для документов, регистров и примитивных типов оператор недоступен, и попытка его использования вызовет ошибку при выполнении запроса.

Список значений, таблица значений и соответствие вместо массива

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

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

Соответствие и структура параметром запроса не поддерживаются. Если ключи соответствия — это нужный список отбора, преобразуйте их в массив перебором:

МассивКлючей = Новый Массив;

Для Каждого КлючЗначение Из СоответствиеЦен Цикл

МассивКлючей.Добавить(КлючЗначение.Ключ);

КонецЦикла;

Сравнение вариантов

Массив + В (&Параметр)

Универсальный способ для списков до нескольких тысяч элементов. Простой код, но очень длинный список раздувает текст SQL-запроса.

СписокЗначений

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

Временная таблица

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

Большие списки: временная таблица вместо параметра

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

Решение — передать таблицу значений во временную таблицу и соединиться с ней в основном запросе:

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

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

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

"ВЫБРАТЬ

| Таб.Номенклатура КАК Номенклатура

|ПОМЕСТИТЬ ВТ_Отбор

|ИЗ

| &ТаблицаОтбора КАК Таб

|;

|ВЫБРАТЬ

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

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

|ИЗ

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

| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Отбор КАК Отбор

| ПО Остатки.Номенклатура = Отбор.Номенклатура";

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

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

Дополнительный плюс временной таблицы — можно передавать составной отбор по нескольким колонкам (например, пары «номенклатура + характеристика»), чего параметр-массив сделать не позволяет. Минус — чуть более сложный код и необходимость следить за именами колонок: они должны совпадать с полями, выбираемыми из параметра-таблицы.

Проверка типов и пустого массива

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

ГДЕ

(&КонтрагентыПустые ИЛИ Реализация.Контрагент В (&Контрагенты))

со значением параметра Запрос.УстановитьПараметр("КонтрагентыПустые", МассивКонтрагентов.Количество() = 0). Такой приём стандартен для отчётов, где отбор может быть не заполнен пользователем.

Вторая ситуация — несовпадение типов. Если поле в запросе имеет составной тип, а в массиве лежат значения не того вида, совпадений не будет, и запрос молча вернёт пустую выборку. Проверяйте, что элементы массива имеют тот же тип, что и поле сравнения: для ссылок — тот же вид объекта метаданных, для строк — сопоставимую длину.

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

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

Количество строк выборки
Норма

Строки есть, их число соответствует ожидаемому по тестовым данным

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

Пустая выборка при заведомо существующих данных — проверяйте типы и имя параметра

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

Элементы одного типа, совпадающего с типом поля отбора

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

Смешанные типы или Неопределено среди элементов

Текст запроса
Норма

Параметр в тексте с амперсандом, в УстановитьПараметр — без него, имена совпадают

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

Опечатка в имени — ошибка выполнения или игнорирование условия

Типичные ошибки при передаче массива в запрос

Первая ошибка — передача массива в ВЫБРАТЬ-часть или попытка вывести его в результат. Массив можно использовать только в условиях (ГДЕ, ИМЕЮЩИЕ, параметры виртуальных таблиц), вывести его как поле выборки нельзя.

Вторая — использование массива в параметрах виртуальной таблицы без учёта её логики: например, в параметре «Условие» виртуальной таблицы остатков строковое выражение собирается вручную, и подстановка имени параметра там работает иначе, чем в секции ГДЕ. Надёжнее передавать отбор через штатные параметры виртуальной таблицы или фильтровать в секции ГДЕ основного запроса.

Третья — дубли в массиве. Лишние повторы не ломают запрос, но увеличивают список IN и время его обработки. Перед передачей большого массива полезно свернуть дубликаты через соответствие или Свернуть() у таблицы значений.

Типичные ошибки
01
Передача пустого массива без обработки — запрос возвращает ноль строк, и это выглядит как «данные пропали»
02
Опечатка в имени параметра между УстановитьПараметр и текстом запроса — ошибка «параметр не найден» или неверный отбор
03
Смешение типов в массиве (ссылки разных справочников, строки и числа) — пустая выборка без сообщений об ошибке
04
Передача огромного массива параметром — раздувание SQL-текста, тайм-ауты и ошибки СУБД вместо результата
05
Попытка передать таблицу значений в условие В — нужна либо ВыгрузитьКолонку, либо временная таблица

Массив в параметрах виртуальных таблиц и СКД

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

В схеме компоновки данных массив или список значений передаётся через параметр настройки с включённым признаком «Доступен список значений». Тогда пользователь отчёта может выбрать несколько значений в режиме предприятия, а СКД сама сформирует условие В. В коде это выглядит как установка значения параметра компоновки через КомпоновщикНастроек — массив при этом оборачивается в СписокЗначений.

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

FAQ

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

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

Почему запрос с условием В (&Параметр) возвращает пустую выборку?

Три основные причины: массив пуст, типы элементов не совпадают с типом поля отбора, либо имя параметра в УстановитьПараметр отличается от имени в тексте запроса. Проверьте массив в отладчике непосредственно перед выполнением запроса.

Есть ли ограничение на количество элементов в массиве-параметре?

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

Как передать массив в запрос из динамического списка формы?

Для динамического списка массив передаётся через отбор компоновки: установите элемент отбора с видом сравнения «В списке» и значением в виде списка значений. Свойство ПроизвольныйЗапрос с параметрами работает так же, как обычный объект Запрос.

Чем В ИЕРАРХИИ отличается от обычного В?

Оператор В сравнивает на точное равенство с любым элементом списка. В ИЕРАРХИИ дополнительно включает всех потомков указанных групп иерархического справочника. Для неиерархических данных второй оператор неприменим.

Итог

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

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