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