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

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

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

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

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

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

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

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

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

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

Создаём временную таблицу из таблицы значений

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

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

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

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

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

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

"ВЫБРАТЬ

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

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

|ПОМЕСТИТЬ ВТ_Потребность

|ИЗ

| &ТаблицаПотребности КАК Т";

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

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

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

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

Читаем временную таблицу в основном запросе

Основной запрос обращается к временной таблице по имени, как к обычному источнику. Главное условие — ему назначен тот же менеджер:

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

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

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

"ВЫБРАТЬ

| Потребность.Номенклатура КАК Номенклатура,

| Потребность.Количество КАК Требуется,

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

|ИЗ

| ВТ_Потребность КАК Потребность

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

| ПО Потребность.Номенклатура = Остатки.Номенклатура";

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

Такой подход заметно эффективнее перебора таблицы значений в цикле с запросом на каждую строку: сервер СУБД получает один пакетный запрос вместо тысяч мелких. Для больших списков (тысячи строк и больше) разница во времени выполнения кратная.

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

Приём таблицы из другого запроса и пакетные запросы

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

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

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

"ВЫБРАТЬ Т.Ссылка ПОМЕСТИТЬ ВТ_Документы

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

|ГДЕ Т.Дата МЕЖДУ &Начало И &Конец

|;

|ВЫБРАТЬ Док.Ссылка, Док.СуммаДокумента

|ИЗ ВТ_Документы КАК Док";

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

Способы передать набор данных в запрос

Временная таблица через МенеджерВТ

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

Параметр-массив с условием В (&Массив)

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

Пакетный запрос с ПОМЕСТИТЬ

Подходит, когда источник ВТ — выборка из базы и вся логика умещается в один вызов. Менее гибок при ветвлении алгоритма.

Типичные ошибки и как их диагностировать

Самая частая ошибка — «Таблица не найдена: ВТ_...». Причина почти всегда одна: основному запросу не назначен тот же менеджер, либо менеджер уже закрыт. Проверяйте строку Запрос.МенеджерВременныхТаблиц = МенеджерВТ у каждого запроса цепочки.

Вторая группа ошибок — типы данных. Если в колонке таблицы значений смешаны, например, ссылки разных видов документов, соединение с конкретной таблицей может дать пустой результат без сообщения об ошибке. Признак — запрос выполняется, но строк меньше ожидаемого или ноль. Лечится явной типизацией колонок при создании таблицы значений через Квалификаторы и ОписаниеТипов.

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

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

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

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

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

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

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

Существование ВТ
Норма

Имя таблицы присутствует в МенеджерВТ.Таблицы после первого запроса

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

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

Число строк результата
Норма

Совпадает с ожидаемым количеством по логике соединения

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

Строк меньше или больше — проверяйте типы колонок и дубли ключей

Значения ключевых полей
Норма

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

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

NULL или пустые значения — проблема с типизацией колонок

Ограничения и когда выбрать другой подход

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

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

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

Маршрут решения

Как выбрать подход

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

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

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

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

Почему запрос пишет «Таблица не найдена», хотя я её создал?

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

Как удалить временную таблицу, не закрывая менеджер?

Выполните запрос с текстом УНИЧТОЖИТЬ ИмяТаблицы с тем же менеджером. Это освобождает память и позволяет создать таблицу с тем же именем заново.

Что быстрее: временная таблица или условие В (&Массив)?

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

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

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

Сохраняется ли временная таблица между серверными вызовами?

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

Итог

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

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