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

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

1С: список значений как параметр запроса

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

Передача списка значений в параметр запроса — одна из самых частых задач при разработке на платформе 1С:Предприятие. Типичный сценарий: из формы или обработки получен набор ссылок (номенклатура, контрагенты, документы), и нужно одним запросом выбрать данные по всем элементам этого набора. Правильно оформленный параметр избавляет от циклических запросов в цикле, которые многократно замедляют работу и нагружают СУБД.

Запрос 1С умеет работать со списками двумя способами: напрямую через оператор В (&Параметр) и через помещение списка во временную таблицу. У каждого подхода есть условия применения, ограничения по типам данных и типичные ошибки, из-за которых запрос либо падает с ошибкой, либо возвращает пустой результат. Ниже разобраны оба варианта с рабочим кодом и способами проверки.

Как передать список значений в параметр запроса

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

СписокНоменклатуры = Новый СписокЗначений;

СписокНоменклатуры.Добавить(Номенклатура1);

СписокНоменклатуры.Добавить(Номенклатура2);

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

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

"ВЫБРАТЬ

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

| Товары.Наименование КАК Наименование

|ИЗ

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

|ГДЕ

| Товары.Ссылка В (&СписокНоменклатуры)";

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

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

Оператор В с параметром-списком платформа преобразует в условие IN на уровне SQL. Важно понимать, что в параметр можно передать не только СписокЗначений, но и массив — запрос обработает оба типа одинаково. Массив часто удобнее, когда набор формируется программно, а список значений — когда он приходит из элемента формы или отбора пользователя.

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

Порядок действий
  1. 1
    Сформируйте СписокЗначений или массив с элементами одного типа
  2. 2
    Проверьте, что коллекция не пуста
  3. 3
    В тексте запроса используйте условие Поле В (&ИмяПараметра)
  4. 4
    Передайте коллекцию через УстановитьПараметр до вызова Выполнить
  5. 5
    Выполните запрос и проверьте число строк в результате

Требования к типам элементов списка

Главное условие корректной работы — однородность типов. Если в списке смешаны, например, ссылки на справочник «Номенклатура» и строки с наименованиями, запрос либо вернёт неполный результат, либо завершится ошибкой несоответствия типов. Сравниваемое поле и элементы списка должны быть совместимы по типу: ссылка со ссылкой, строка со строкой, число с числом.

Отдельная тонкость — составные типы. Если поле в запросе имеет составной тип (например, реквизит «Контрагент», который может быть ссылкой на разные справочники), а в списке ссылки только одного вида, условие отработает корректно. Обратная ситуация опаснее: сравнение строки с числом или пустой ссылки с заполненной часто даёт молча пустой результат, который трудно диагностировать.

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

Когда вместо списка использовать временную таблицу

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

Альтернатива — поместить данные во временную таблицу через МенеджерВременныхТаблиц. Для этого список сначала преобразуют в таблицу значений с одной колонкой, передают её параметром и помещают во временную таблицу конструкцией ПОМЕСТИТЬ:

ТаблицаОтбора = Новый ТаблицаЗначений;

ТаблицаОтбора.Колонки.Добавить("Номенклатура",

Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

Для Каждого Элемент Из СписокНоменклатуры Цикл

ТаблицаОтбора.Добавить().Номенклатура = Элемент.Значение;

КонецЦикла;

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

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|;

|ВЫБРАТЬ

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

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

|ИЗ

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

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

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

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

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

Такой подход даёт три преимущества: можно явно задать тип колонки через ОписаниеТипов, временную таблицу можно индексировать (ИНДЕКСИРОВАТЬ ПО) для ускорения соединения, и одну и ту же выборку можно использовать в нескольких пакетных запросах внутри одного менеджера временных таблиц.

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

Оператор В (&Список)

Подходит для десятков и сотен элементов и простой фильтрации. Не позволяет соединять список с другими таблицами и контролировать типы.

Временная таблица из таблицы значений

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

Отбор в виртуальной таблице

Для регистров эффективнее передавать условие в параметры виртуальной таблицы (например, Остатки(, Номенклатура В (&Список))), чем фильтровать после выборки.

Типичные ошибки и как их диагностировать

Самая частая ошибка — передача в параметр не коллекции, а одиночного значения или, наоборот, попытка сравнить поле со списком через знак равенства: ГДЕ Товары.Ссылка = &СписокНоменклатуры. В первом случае запрос не найдёт ничего или выдаст ошибку, во втором — платформа сообщит о неверном типе операнда сравнения.

Вторая группа ошибок связана с пустым списком. Условие В (&ПустойСписок) не вызывает исключения — оно просто отсекает все строки. Если запрос внезапно возвращает пустой результат, первым делом проверьте количество элементов в параметре. Хорошая практика — явная защита в коде:

Если СписокНоменклатуры.Количество() = 0 Тогда

Возврат Новый ТаблицаЗначений; // нечего выбирать

КонецЕсли;

Третья группа — неявное приведение типов при заполнении списка из строки. Если список собирается из текстового поля или файла, элементы могут оказаться строками вместо ссылок. Перед запросом преобразуйте их в ссылки через Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаGUID)) или поиск по коду, иначе сравнение со ссылочным полем ничего не найдёт.

Типичные ошибки
01
Условие Поле = &Список вместо Поле В (&Список) — синтаксическая ошибка или пустой результат
02
Передача пустого списка без проверки — запрос молча возвращает ноль строк
03
Смешение типов в одном списке (ссылки и строки) — часть элементов не участвует в отборе
04
Дубли и пустые ссылки в списке — лишний объём передаваемых данных и ложные совпадения
05
Использование В для длинных списков там, где нужно соединение, — потеря производительности

Производительность и ограничения

С точки зрения производительности оператор В с параметром-списком эффективен, пока список умеренного размера и по полю отбора есть индекс. Для ссылочных полей индекс обычно существует по умолчанию, поэтому отбор по списку ссылок — быстрая операция. Проблемы начинаются при отборе по неиндексированным строковым реквизитам или при очень больших списках.

Если список содержит тысячи элементов, переносите его во временную таблицу и добавляйте ИНДЕКСИРОВАТЬ ПО по полю соединения. Это особенно заметно при соединении с виртуальными таблицами регистров. Также помните, что параметр-список каждый раз передаётся на сервер целиком: при вызове запроса в цикле на клиенте это создаёт многократные серверные вызовы.

Ещё одно ограничение: список значений нельзя передать в параметр виртуальной таблицы регистра напрямую в некоторых конструкциях — там условие записывается в строке параметров виртуальной таблицы, но сам параметр-список внутри этой строки допустим: Остатки(, Номенклатура В (&Список)). Проверяйте синтаксис конструктором запроса, если сомневаетесь.

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

После выполнения запроса убедитесь, что результат соответствует ожиданиям, прежде чем передавать его дальше в обработку. Минимальный набор проверок: результат не пуст, количество строк не превышает количество элементов списка (для выборки из справочника), все найденные ссылки действительно входят в исходный список.

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

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

Количество строк результата
Норма

Больше нуля и не превышает размер списка для выборки из справочника

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

Ноль строк при непустом списке — проверяйте типы и содержимое параметра

Состав ссылок в выборке
Норма

Каждая ссылка есть в исходном списке

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

Лишние записи — вероятно, условие сформулировано неверно

Время выполнения
Норма

Сопоставимо с выборкой по одному значению

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

Заметная задержка — список слишком велик, переходите на временную таблицу

При отладке удобно временно вывести параметр в сообщение: Сообщить("Элементов в списке: " + СписокНоменклатуры.Количество()). Это позволяет быстро отличить проблему «пустой параметр» от проблемы «неверный текст запроса». В консоли запросов тот же приём выполняется заполнением параметра вручную на вкладке «Параметры».

Итог

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

Список значений передаётся через УстановитьПараметр и используется с оператором В. Элементы должны быть одного типа и совместимы с полем отбора. Пустой список проверяйте до запроса. Для больших наборов и соединений преобразуйте список в таблицу значений и поместите её во временную таблицу.

Частые вопросы

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

Да. Оператор В (&Параметр) одинаково принимает и массив, и список значений. Массив удобнее при программном формировании набора, список — когда данные приходят из элементов формы. Внутри запроса различий нет.

Почему запрос с условием В (&Список) возвращает пустой результат?

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

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

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

Как передать список в параметр виртуальной таблицы регистра?

Условие записывается прямо в параметрах виртуальной таблицы: РегистрНакопления.Товары.Остатки(, Номенклатура В (&Список)). Сам параметр устанавливается обычным способом через УстановитьПараметр. Такой отбор эффективнее, чем фильтрация результата после выборки.

Чем отличается В от В ИЕРАРХИИ при работе со списком?

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

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

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