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