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