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

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

Работа с временными таблицами в 1С — это стандарт де-факто для разработки сложных отчетов и обработок. Однако многие разработчики сталкиваются с неприятной особенностью: если временная таблица была создана в одном запросе и передана в другой через МенеджерВременныхТаблиц, стандартный Конструктор запроса отказывается распознавать ее структуру. При попытке открыть такой запрос мы получаем сообщение об ошибке: «Таблица не найдена» или «У данной таблицы отсутствуют выбранные поля».

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

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

Для начала проанализируем ситуацию с точки зрения платформы. Конструктор запроса — это инструмент статического анализа текста. Когда мы открываем его, он пытается распарсить текст запроса и сопоставить имена таблиц с метаданными конфигурации или с описаниями внутри текущего текста запроса.

Если мы используем МенеджерВременныхТаблиц, описание структуры таблицы хранится в оперативной памяти сервера (или в системной базе tempdb SQL-сервера) в контексте конкретного сеанса. Конструктор, работающий внутри конфигуратора, не имеет доступа к данным, которые были сформированы в режиме «Предприятие». Он видит только «голый» текст: ВЫБРАТЬ * ИЗ ВтДоговоры. Поскольку таблицы ВтДоговоры нет в метаданных и она не создается выше по тексту в этом же пакете, конструктор выдает ошибку.

Решение 1. Переход на пакетные запросы

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

Рассмотрим пример создания пакетного запроса:


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

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

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

Решение 2. Трюк с «фиктивным» описанием для Конструктора

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

Разберем по шагам, как реализовать этот метод:

  1. В конструкторе вставляем первым запросом пакета выборку из любого справочника, которая создает таблицу с таким же именем и полями, как в вашем менеджере.
  2. Работаем в конструкторе со вторым запросом пакета (основным).
  3. Перед выполнением запроса в коде программно отрезаем «фиктивную» часть.

Посмотрим на пример кода, реализующего этот подход:


// В конструкторе текст выглядит так:
// ВЫБРАТЬ ЗНАЧЕНИЕ(Справочник.ДоговорыКонтрагентов.ПустаяСсылка) КАК Договор ПОМЕСТИТЬ ВтДоговоры;
// //МАРКЕР_КОНЦА_ОПИСАНИЯ
// ВЫБРАТЬ Договор ИЗ ВтДоговоры ГДЕ Сумма > 100

ТекстДляКонструктора = Запрос.Текст;
ПозицияМаркера = СтрНайти(ТекстДляКонструктора, "//МАРКЕР_КОНЦА_ОПИСАНИЯ");
Если ПозицияМаркера > 0 Тогда
    // Отрезаем всё лишнее, оставляя только реальный запрос
    Запрос.Текст = Сред(ТекстДляКонструктора, ПозицияМаркера + СтрДлина("//МАРКЕР_КОНЦА_ОПИСАНИЯ") + 1);
КонецЕсли;

Запрос.МенеджерВременныхТаблиц = МойМенеджерВТ;
Результат = Запрос.Выполнить();

Решение 3. Использование Таблицы Значений (ТЗ)

Если временная таблица не содержит миллионы записей (до 20-50 тысяч строк), хорошей альтернативой МенеджерВременныхТаблиц будет выгрузка данных в ТаблицаЗначений.

Рассмотрим, как это помогает в работе с конструктором:

  1. Вы один раз получаете данные и выгружаете их в ТЗ.
  2. В каждом последующем запросе вы используете эту ТЗ как параметр.
  3. В конструкторе запроса на закладке «Таблицы и поля» вы можете нажать кнопку «Создать описание временной таблицы» и вручную описать поля. Конструктор запомнит их, и вы сможете визуально связывать таблицы.

Пример кода с загрузкой ТЗ в запрос:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ТЗДоговоры.Договор
    |ПОМЕСТИТЬ ВтДоговоры
    |ИЗ
    |    &ТЗДоговоры КАК ТЗДоговоры
    |;
    |ВЫБРАТЬ * ИЗ ВтДоговоры";

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

Важные замечания о производительности

Проанализируем ситуацию, упомянутую в обсуждении: стоит ли долго держать открытым МенеджерВременныхТаблиц?

Риски использования МВТ:

Рекомендация: Если данные (например, список из 17 000 договоров) нужны вам для разных действий в форме, лучше всего один раз получить их в массив ссылок или Таблицу Значений. Передача массива ссылок в параметр ГДЕ Ссылка В (&МассивДоговоров) обычно работает быстрее и стабильнее, чем поддержание постоянного МенеджерВременныхТаблиц в памяти сервера в течение всего рабочего дня пользователя.

Заключение

Мы выяснили, что «слепота» конструктора запросов — это не баг, а архитектурная особенность. Для комфортной разработки мы рекомендуем использовать пакетные запросы везде, где это возможно. Если же бизнес-логика требует передачи таблиц между вызовами, используйте метод программной отсечки описания или ручное описание полей в конструкторе при использовании внешних источников данных. И не забывайте про индексацию временных таблиц по полям связи — это критически важно для производительности ваших запросов!

← На главную