Что лежит во временной таблице: три способа заглянуть внутрь

· 9 мин

Содержание

Прочитать временную таблицу в 1С можно тремя способами: следующим запросом пакета ВЫБРАТЬ * ИЗ ВТ_Имя, через коллекцию МенеджерВременныхТаблиц.Таблицы и метод ПолучитьДанные() или методом ВыполнитьПакетСПромежуточнымиДанными(). Первый работает в любой версии 8.x, два других — в платформе 8.3 (появились в релизах 8.3.4–8.3.5) и удобнее всего для отладки.

Какой выбрать? Если данные нужны дальше в алгоритме — читайте запросом. Если нужно понять, почему отчёт или проведение считают не то, — смотрите содержимое через менеджер прямо в отладчике или включайте промежуточные данные пакета. Консоль запросов полезна, когда кода под рукой нет, а запрос есть.

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

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

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	Номенклатура.Ссылка КАК Номенклатура,
|	Номенклатура.Артикул КАК Артикул
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
|	Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|	НЕ Номенклатура.ЭтоГруппа
|
|ИНДЕКСИРОВАТЬ ПО
|	Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|	ВТ_Товары.Номенклатура,
|	ВТ_Товары.Артикул
|ИЗ
|	ВТ_Товары КАК ВТ_Товары";

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

Что здесь важно:

  • 📌 Имя таблицы пишется без префиксов вроде Справочник. — просто ВТ_Товары. Префикс ВТ_ — соглашение, а не требование платформы, но с ним текст читается проще.
  • 📌 Метод Выполнить() возвращает результат последнего запроса пакета. Поэтому читающий запрос ставят в конец.
  • 📌 Псевдоним КАК ВТ_Товары необязателен, но конструктор запросов его добавляет, и с ним удобнее делать соединения.
  • 📌 К временной таблице можно присоединять таблицы базы: ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(...), фильтровать ГДЕ Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ВТ_Товары).

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

Сколько живёт временная таблица и где она хранится

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

СитуацияСколько живёт ВТ
У запроса не задан МенеджерВременныхТаблицТолько пока выполняется пакет. После Выполнить() её уже нет
Задан Запрос.МенеджерВременныхТаблицПока жив объект менеджера или до вызова Менеджер.Закрыть()
В пакете есть УНИЧТОЖИТЬ ВТ_ИмяДо этого запроса пакета

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

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

Запрос1 = Новый Запрос;
Запрос1.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос1.Текст = "ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ_Остатки ИЗ ...";
Запрос1.Выполнить();

// Где-то дальше в той же процедуре или в вызванной функции
Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос2.Текст = "ВЫБРАТЬ * ИЗ ВТ_Остатки";
Выборка = Запрос2.Выполнить().Выбрать();

Где физически лежат данные:

  • 🗄️ Клиент-серверный вариант — во временных таблицах СУБД (в MS SQL это база tempdb, в PostgreSQL — временные таблицы сеанса).
  • 💾 Файловый вариант — во временных файлах и памяти процесса, который выполняет запрос.

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

Менеджер с крупными временными таблицами держит ресурсы СУБД, пока жив. В длинных обработках закрывайте его явно: МенеджерВТ.Закрыть(), а ненужные промежуточные таблицы удаляйте запросом УНИЧТОЖИТЬ.

Программное чтение: выборка, выгрузка и коллекция Таблицы

Обычная выборка строк

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

Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
	Сообщить(СтрШаблон("%1 — %2", Выборка.Номенклатура, Выборка.Артикул));
КонецЦикла;

// Или целиком
ТЗ = Результат.Выгрузить();

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

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

Чтение ВТ без отдельного запроса

С платформы 8.3.5 у менеджера есть свойство Таблицы. Это коллекция временных таблиц, которые в нём сейчас лежат. У каждого элемента есть Имя, Колонки и метод ПолучитьДанные(), который возвращает РезультатЗапроса.

ТаблицаВТ = МенеджерВТ.Таблицы.Найти("ВТ_Остатки");
Если ТаблицаВТ <> Неопределено Тогда
	ТЗ = ТаблицаВТ.ПолучитьДанные().Выгрузить();
КонецЕсли;

// Список всех временных таблиц менеджера
Для Каждого Т Из МенеджерВТ.Таблицы Цикл
	Сообщить(Т.Имя);
КонецЦикла;

Так удобно проверять, создалась ли таблица, и смотреть её состав колонок без правки текста запроса.

Промежуточные данные пакета

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

Результаты = Запрос.ВыполнитьПакетСПромежуточнымиДанными();
ДанныеВТ = Результаты[0].Выгрузить(); // первый запрос пакета — ВТ_Товары

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

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

Пример: на каком шаге пакета пропали строки

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

Результаты = Запрос.ВыполнитьПакет();
Для Индекс = 0 По Результаты.ВГраница() Цикл
	Р = Результаты[Индекс];
	Если Р = Неопределено Тогда
		Продолжить; // страховка на случай запроса без результата
	КонецЕсли;
	ТЗ = Р.Выгрузить();
	Если ТЗ.Колонки.Найти("Количество") <> Неопределено И ТЗ.Количество() = 1 Тогда
		Сообщить(СтрШаблон("Запрос %1: в ВТ помещено %2", Индекс + 1, Формат(ТЗ[0].Количество, "ЧН=0; ЧГ=0")));
	Иначе
		Сообщить(СтрШаблон("Запрос %1: строк в результате %2", Индекс + 1, Формат(ТЗ.Количество(), "ЧН=0; ЧГ=0")));
	КонецЕсли;
КонецЦикла;

Если, например, во второй ВТ 1 200 строк, а в третьей уже 40, — ищите проблему в условии или соединении третьего запроса. Чаще всего это внутреннее соединение там, где нужно левое, или отбор по пустому параметру.

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

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

Консоль запросов

Консоль — внешняя обработка. Её открывают в режиме 1С:Предприятие через главное меню: ≡ → Файл → Открыть. Нужно право на интерактивное открытие внешних обработок; у обычного пользователя его часто нет.

Дальше порядок такой:

  1. Вставьте текст запроса целиком, со всеми запросами пакета.
  2. Если нужно увидеть конкретную ВТ, а не итог, добавьте в конец пакета ВЫБРАТЬ * ИЗ ВТ_Имя.
  3. Задайте параметры (&Период, &Организация) — без них запрос упадёт или вернёт пустоту.
  4. Выполните запрос и смотрите результат последнего пакета.

Многие сборки консоли умеют показывать результат каждого запроса пакета отдельно — они как раз используют промежуточные данные. Если в вашей консоли такого режима нет, приём с ВЫБРАТЬ * в конце работает всегда.

Отладчик

Самый быстрый способ, когда запрос сидит в типовом коде:

  1. Поставьте точку останова в Конфигураторе или EDT сразу после Запрос.Выполнить().
  2. Когда выполнение остановится, откройте окно вычисления выражения (Shift+F9).
  3. Введите выражение:
Запрос.МенеджерВременныхТаблиц.Таблицы.Найти("ВТ_Остатки").ПолучитьДанные().Выгрузить()

Отладчик покажет таблицу значений, её можно развернуть и просмотреть строки.

Если у запроса менеджер не задан, после Выполнить() таблиц уже нет. Тогда вычислите в отладчике Запрос.ВыполнитьПакетСПромежуточнымиДанными() прямо на точке останова перед выполнением — получите массив результатов по всем запросам пакета.

Почему временная таблица не читается: разбор ошибок

Диагностика: выберите симптом

Ещё две частые ловушки, которые не дают ошибки, но портят результат:

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

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

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

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

Практическое правило:

  • 🔹 Данные дальше идут в соединение с регистрами и справочниками — оставляйте их во временной таблице. Выгрузка в ТЗ и обратная загрузка параметром удвоит работу.
  • 🔹 Нужно пройти по строкам, что-то посчитать, поменять значения или показать пользователю — выгружайте в таблицу значений.
  • 🔹 Таблицу значений из кода нужно использовать в запросе — поместите её во временную таблицу первым запросом пакета:
Запрос.Текст =
"ВЫБРАТЬ
|	Т.Номенклатура КАК Номенклатура,
|	Т.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Строки
|ИЗ
|	&ТаблицаСтрок КАК Т";
Запрос.УстановитьПараметр("ТаблицаСтрок", ТЗ);

Колонки ТЗ должны быть типизированы: ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число")).

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

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

Можно ли прочитать временную таблицу из другого сеанса или пользователя?
Нет. Временные таблицы видны только в своём менеджере, а менеджер живёт в одном сеансе. Для обмена данными между сеансами нужны регистры сведений или хранилище значений.
Можно ли сохранить МенеджерВременныхТаблиц в реквизите формы?
Нет. Объект существует только на сервере и не сериализуется. При каждом серверном вызове временные таблицы придётся создавать заново или хранить данные в другом виде.
Как узнать, какие колонки есть у временной таблицы?
Через МенеджерВТ.Таблицы.Найти("ВТ_Имя").Колонки: у каждой колонки есть имя и тип значения. Работает в платформе 8.3.5 и новее.
Влияет ли регистр букв в имени ВТ?
Нет, язык запросов к регистру нечувствителен: ВТ_Товары и вт_товары — одна таблица.
Нужно ли уничтожать временные таблицы в конце процедуры?
Если менеджер локальный, он уничтожится сам при выходе из процедуры. Явное УНИЧТОЖИТЬ или Закрыть() нужно в длинных обработках и циклах, где таблицы накапливаются.