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

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

Временная таблица как параметр запроса в 1С

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

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

Механизм прост: таблица значений передаётся в запрос как параметр, в тексте запроса она выбирается конструкцией ВЫБРАТЬ ... ПОМЕСТИТЬ ИмяТаблицы ИЗ &Параметр КАК Источник, а дальше временная таблица используется в соединениях, объединениях и условиях. Для повторного использования временных таблиц между несколькими запросами применяется объект МенеджерВременныхТаблиц.

В этом материале разобраны оба подхода — разовая передача таблицы через параметр и работа через менеджер временных таблиц, приведены готовые примеры кода, ограничения платформы, типичные ошибки и способы проверить, что данные попали в запрос корректно.

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

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

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

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

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

"ВЫБРАТЬ

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

| Товары.Количество КАК Количество

|ПОМЕСТИТЬ ВТ_Товары

|ИЗ

| &ТаблицаТоваров КАК Товары

|;

|////////////////////////////////////////////////////////////

|ВЫБРАТЬ

| ВТ_Товары.Номенклатура,

| ВТ_Товары.Количество,

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

|ИЗ

| ВТ_Товары КАК ВТ_Товары

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

| ПО ВТ_Товары.Номенклатура = Остатки.Номенклатура";

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

Обратите внимание на синтаксис обращения к параметру-таблице: ИЗ &ТаблицаТоваров КАК Товары. Колонки обращаются по именам колонок таблицы значений. Если колонка в таблице значений называется иначе, чем реквизит в базе, это не проблема — вы задаёте псевдонимы в секции ВЫБРАТЬ.

Порядок действий
  1. 1
    Сформируйте таблицу значений и явно опишите типы колонок через ОписаниеТипов
  2. 2
    Установите таблицу как параметр: Запрос.УстановитьПараметр("ТЗ", ТаблицаЗначений)
  3. 3
    В тексте запроса выберите данные: ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ_Имя ИЗ &ТЗ КАК Источник
  4. 4
    Используйте временную таблицу в соединениях и условиях далее по тексту пакетного запроса
  5. 5
    Выполните запрос и проверьте результат выгрузкой в таблицу значений

Менеджер временных таблиц: зачем он нужен

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

Менеджер создаётся один раз и назначается всем запросам, которые должны видеть общие временные таблицы:

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

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

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

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

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

"ВЫБРАТЬ ТЗ.Контрагент КАК Контрагент

|ПОМЕСТИТЬ ВТ_Контрагенты

|ИЗ &ТЗ КАК ТЗ";

Запрос1.Выполнить();

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

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

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

"ВЫБРАТЬ *

|ИЗ РегистрНакопления.Взаиморасчеты.Обороты(,,, Контрагент В

| (ВЫБРАТЬ Контрагент ИЗ ВТ_Контрагенты)) КАК Обороты";

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

Второй запрос не знает ничего о параметре первого, но видит таблицу ВТ_Контрагенты, потому что оба запроса работают через общий менеджер. Временные таблицы существуют, пока существует менеджер или пока их явно не уничтожить запросом УНИЧТОЖИТЬ ВТ_Контрагенты.

Типизация колонок: главное условие корректной работы

Самая частая причина проблем при передаче таблицы в запрос — неявная типизация колонок. Если вы добавили колонку просто через ТаблицаЗначений.Колонки.Добавить("Сумма") без указания типа, платформа попытается определить тип по данным, и при пустой таблице или смешанных значениях запрос может упасть с ошибкой или вернуть некорректные результаты соединения.

Всегда описывайте типы явно:

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

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

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

ТаблицаЗначений.Колонки.Добавить("Количество",

Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));

ТаблицаЗначений.Колонки.Добавить("Комментарий",

Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(100)));

Особое внимание уделите ссылочным полям: если в колонке «Номенклатура» окажется строка вместо ссылки, соединение с регистром по этому полю не найдёт ни одной записи, и вы получите пустой результат без какой-либо ошибки. Такая ошибка диагностируется тяжело, потому что запрос формально выполняется успешно.

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

Типичные ошибки
01
Колонки без описания типов — запрос падает на пустой таблице или соединение работает некорректно
02
Смешение типов в одной колонке (ссылки разных справочников или строка вместо ссылки) — соединение молча возвращает пустой результат
03
Обращение к временной таблице из другого запроса без общего менеджера — ошибка «Таблица не найдена»
04
Повторное выполнение запроса с ПОМЕСТИТЬ в ту же таблицу без УНИЧТОЖИТЬ — ошибка «Таблица уже существует»
05
Передача огромной таблицы значений через параметр без отбора — рост потребления памяти и медленное выполнение

Использование параметра-таблицы без ПОМЕСТИТЬ

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

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

"ВЫБРАТЬ Ссылка

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

|ГДЕ Контрагент В (&СписокКонтрагентов)";

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

Однако если одна и та же таблица значений используется в тексте запроса два и более раз (например, в двух объединениях), выгоднее один раз поместить её во временную таблицу и дальше ссылаться на неё. Повторное обращение к параметру-таблице заставляет СУБД каждый раз материализовать данные заново.

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

Массив/список в условии В

Подходит для отбора по одному полю. Ограничение: нельзя передать несколько связанных колонок и соединять по ним.

Таблица значений через параметр + ПОМЕСТИТЬ

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

Менеджер временных таблиц

Нужен, когда временная таблица используется в нескольких запросах или собирается поэтапно. Требует контроля времени жизни и уничтожения таблиц.

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

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

Практические рекомендации по оптимизации:

  • Передавайте только нужные колонки: лишние поля увеличивают объём передаваемых данных и замедляют материализацию.
  • Если по временной таблице идёт соединение, проиндексируйте её: ПОМЕСТИТЬ ВТ_Товары ИНДЕКСИРОВАТЬ ПО Номенклатура — это заметно ускоряет соединения на больших объёмах.
  • Уничтожайте временные таблицы, которые больше не нужны, особенно в длинных пакетных запросах: УНИЧТОЖИТЬ ВТ_Товары освобождает память и tempdb на СУБД.
  • Не передавайте одну и ту же таблицу параметром в цикле — вынесите её в менеджер временных таблиц один раз.

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

Проверка результата и отладка

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

Программно проверить содержимое временной таблицы можно выборкой из неё через тот же менеджер:

ЗапросПроверки = Новый Запрос;

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

ЗапросПроверки.Текст = "ВЫБРАТЬ * ИЗ ВТ_Контрагенты";

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

// Проверка.Количество() — сколько строк реально попало во временную таблицу

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

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

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

Число строк во временной таблице
Норма

Совпадает с числом строк исходной таблицы значений

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

Строк меньше или ноль — проблема с параметром или типами колонок

Результат соединения с таблицей базы
Норма

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

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

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

Повторное выполнение пакетного запроса
Норма

Выполняется без ошибок

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

Ошибка «Таблица уже существует» — нужно УНИЧТОЖИТЬ таблицу или новый менеджер

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

Можно ли передать таблицу значений в запрос без менеджера временных таблиц?

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

Почему запрос выдаёт ошибку «Неверные параметры в операции сравнения» при соединении?

Почти всегда причина в несовпадении типов полей соединения: например, в таблице значений колонка имеет тип Строка, а в базе — ссылка на справочник. Приведите тип колонки к нужному через ОписаниеТипов при создании таблицы или используйте ВЫРАЗИТЬ в тексте запроса.

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

Табличную часть нужно сначала выгрузить: ТЗ = ДокументОбъект.Товары.Выгрузить(). Полученная таблица значений передаётся параметром обычным способом. Типы колонок при выгрузке берутся из метаданных, поэтому дополнительная типизация обычно не требуется.

Что делать, если временная таблица нужна в другой процедуре или функции?

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

Есть ли ограничение на размер передаваемой таблицы значений?

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

Можно ли изменить данные во временной таблице после её создания?

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

Итог

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

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