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

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

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

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

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

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

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

Как устроен механизм временных таблиц в 1С

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

Запрос «увидит» временную таблицу только при одном условии: его свойство МенеджерВременныхТаблиц ссылается на тот же объект менеджера, в котором таблица создана. Если менеджеры разные — запрос завершится ошибкой «Таблица не найдена». Это самая частая причина проблем у начинающих разработчиков.

Создание менеджера и помещение таблицы

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

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

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

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

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

"ВЫБРАТЬ

| Продажи.Номенклатура КАК Номенклатура,

| СУММА(Продажи.Количество) КАК Количество

|ПОМЕСТИТЬ ВТ_Продажи

|ИЗ

| РегистрНакопления.Продажи КАК Продажи

|ГДЕ

| Продажи.Период МЕЖДУ &НачалоПериода И &КонецПериода

|СГРУППИРОВАТЬ ПО

| Продажи.Номенклатура";

Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДатаСеанса()));

Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДатаСеанса()));

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

Обратите внимание: результат выполнения такого запроса не выгружается в таблицу значений — метод Выполнить() просто создаёт таблицу ВТ_Продажи в менеджере. Имя таблицы принято начинать с префикса ВТ_, чтобы в сложных пакетных запросах сразу отличать временные таблицы от таблиц базы данных.

Использование временной таблицы во втором запросе

Теперь создаём второй запрос и назначаем ему тот же менеджер. В тексте запроса временная таблица указывается в секции ИЗ по имени, без каких-либо дополнительных объявлений.

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

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

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

"ВЫБРАТЬ

| ВТ_Продажи.Номенклатура КАК Номенклатура,

| ВТ_Продажи.Количество КАК Продано,

| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток

|ИЗ

| ВТ_Продажи КАК ВТ_Продажи

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

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

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

После выполнения переменная Результат содержит таблицу значений с объединёнными данными. Сама временная таблица остаётся в менеджере и может использоваться дальше — в третьем, четвёртом запросе и так далее, пока менеджер не закрыт.

Порядок действий
  1. 1
    Создайте объект МенеджерВременныхТаблиц и сохраните его в переменной
  2. 2
    Назначьте менеджер первому запросу и выполните запрос с конструкцией ПОМЕСТИТЬ ИмяТаблицы
  3. 3
    Назначьте тот же менеджер второму запросу и обратитесь к таблице по имени в секции ИЗ
  4. 4
    Выгрузите результат второго запроса методом Выполнить().Выгрузить()
  5. 5
    Проверьте результат: количество строк и содержимое колонок должны соответствовать ожидаемой выборке

Пакетный запрос как альтернатива нескольким объектам

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

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

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

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

"ВЫБРАТЬ Номенклатура, СУММА(Количество) КАК Количество

|ПОМЕСТИТЬ ВТ_Продажи

|ИЗ РегистрНакопления.Продажи КАК Продажи

|СГРУППИРОВАТЬ ПО Номенклатура

|;

|ВЫБРАТЬ * ИЗ ВТ_Продажи КАК ВТ_Продажи";

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

ТаблицаПродаж = МассивРезультатов[1].Выгрузить();

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

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

Отдельные объекты Запрос с общим менеджером

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

Пакетный запрос

Компактно, один текст, один вызов. Ограничение: между подзапросами нельзя вставить код на встроенном языке, отлаживать сложнее.

Передача таблицы значений параметром

Нужна, когда источник данных — не запрос, а код: таблица значений передаётся в параметр и помещается через ВЫБРАТЬ ... ИЗ &Таблица. Требует описания типов колонок.

Передача таблицы значений как временной таблицы

Частая задача — передать в запрос не результат другого запроса, а таблицу значений, сформированную в коде (например, загруженную из файла). Для этого таблица передаётся через параметр, а в тексте запроса используется конструкция ВЫБРАТЬ ... ИЗ &ИмяПараметра с явным перечислением колонок.

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

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

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

"ВЫБРАТЬ

| Таб.Код КАК Код,

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

|ПОМЕСТИТЬ ВТ_Загруженные

|ИЗ

| &ТаблицаДанных КАК Таб";

Запрос.УстановитьПараметр("ТаблицаДанных", ТаблицаИзФайла);

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

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

Управление временем жизни и очистка таблиц

Временные таблицы занимают ресурсы сервера, пока существует менеджер. В длительных обработках с большими выборками это заметно влияет на производительность. Удалить ненужную таблицу можно командой УНИЧТОЖИТЬ ИмяТаблицы в отдельном запросе с тем же менеджером, а весь менеджер — методом Закрыть().

ЗапросОчистка = Новый Запрос;

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

ЗапросОчистка.Текст = "УНИЧТОЖИТЬ ВТ_Продажи";

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

МенеджерВТ.Закрыть();

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

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

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

Наличие таблицы в менеджере
Норма

МенеджерВТ.Таблицы содержит элемент с нужным именем

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

Таблицы нет — запрос с ПОМЕСТИТЬ не выполнялся или упал с ошибкой

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

Запрос выполняется, выборка содержит строки

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

Ошибка «Таблица не найдена» — у запросов разные менеджеры

Содержимое выборки
Норма

Количество строк и значения колонок соответствуют исходным данным

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

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

Типичные ошибки и ограничения

Большинство проблем с временными таблицами сводится к нескольким повторяющимся сценариям. Знание их экономит часы отладки.

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

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

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

При отладке сложных цепочек запросов удобно после каждого ПОМЕСТИТЬ временно добавлять выборку ВЫБРАТЬ * ИЗ ВТ_Имя и выводить количество строк. Это позволяет быстро локализовать шаг, на котором данные теряются, вместо анализа всего пакета целиком.
ПЗ
Практическое замечание
Итог

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

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

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

Можно ли использовать временную таблицу в консоли запросов?

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

Как узнать, сколько строк во временной таблице?

Выполните запрос с текстом ВЫБРАТЬ КОЛИЧЕСТВО(*) ИЗ ВТ_Имя с тем же менеджером. Некоторые инструменты разработчика также показывают содержимое временных таблиц через коллекцию МенеджерВТ.Таблицы.

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

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

Что произойдёт с временными таблицами при завершении процедуры?

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

Можно ли передать временную таблицу между клиентом и сервером?

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

Чем временная таблица лучше вложенного запроса?

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