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