Работа с объектом СхемаЗапроса в 1С:Предприятие 8.3 открывает широкие возможности для динамического построения сложных запросов. Однако при попытке добавить в схему источник, который является внешней временной таблицей (передаваемой как параметр через &ТаблицаЗначений), разработчики часто сталкиваются с трудностями. Система может выдавать ошибку о том, что таблица не найдена, поскольку стандартный метод добавления источника ожидает увидеть имя таблицы из метаданных конфигурации. Для интерактивной отладки и анализа динамических запросов подойдёт консоль запросов с поддержкой схемы запроса.
В этой статье мы подробно разберем, как правильно сконструировать запрос через СхемаЗапроса, если источником данных выступает внешняя таблица значений, которую необходимо поместить во временную таблицу внутри пакета запроса.
Рассмотрим ситуацию: нам нужно программно создать запрос, состоящий из двух пакетов. В первом пакете мы берем данные из параметра &ТаблицаПравилПервогоУровня и помещаем их во временную таблицу. Во втором пакете мы выбираем данные из этой временной таблицы. Проанализируем типичную ошибку начинающего разработчика:
СхемаЗапроса = Новый СхемаЗапроса;
ОператорСхемы = СхемаЗапроса.ПакетЗапросов[0].Операторы[0];
// ОШИБКА: Система ищет таблицу в метаданных по имени строки
ОператорСхемы.Источники.Добавить("&ТаблицаПравилПервогоУровня", "ТаблицаПравилПервогоУровня");
Проблема заключается в том, что метод Добавить() коллекции Источники при получении строки в качестве первого параметра пытается разрешить её как путь к объекту метаданных (например, Справочник.Номенклатура). Поскольку таблицы с именем &ТаблицаПравилПервогоУровня в конфигурации не существует, возникает исключение.
Для того чтобы система поняла, что источником является именно внешнее описание таблицы, необходимо использовать специальный объект. Выясним причину успеха: использование типа ОписаниеВременнойТаблицыСхемыЗапроса позволяет явно указать схеме, что мы описываем структуру таблицы, которая будет предоставлена в момент выполнения запроса.
Рассмотрим правильный алгоритм действий:
СхемаЗапроса.Тип("ОписаниеВременнойТаблицыСхемыЗапроса").ТаблицаДляПомещения для сохранения результата во временную таблицу.Посмотрим на пример корректного кода:
СхемаЗапроса = Новый СхемаЗапроса;
// Первый пакет запроса - здесь мы описываем выборку из параметра
Пакет1 = СхемаЗапроса.ПакетЗапросов[0];
ОператорСхемы = Пакет1.Операторы[0];
// Добавляем описание внешней временной таблицы
Источник = ОператорСхемы.Источники.Добавить(Тип("ОписаниеВременнойТаблицыСхемыЗапроса"), "&ТаблицаПравилПервогоУровня");
Источник.Псевдоним = "ТаблицаПравилПервогоУровня";
// Добавляем поля, которые мы планируем выбирать
ОператорСхемы.ВыбираемыеПоля.Добавить("ТаблицаПравилПервогоУровня.Родитель", 0);
ОператорСхемы.ВыбираемыеПоля.Добавить("ТаблицаПравилПервогоУровня.Правило", 1);
// Указываем имя временной таблицы, куда будут помещены данные
Пакет1.ТаблицаДляПомещения = "ТаблицаПравилПервогоУровня";
Проанализируем ситуацию глубже. Хотя приведенный выше код работоспособен, СхемаЗапроса может не знать о составе полей таблицы &ТаблицаПравилПервогоУровня до компиляции. Чтобы сделать код более надежным и избежать ошибок «Поле не найдено» при программной настройке полей, рекомендуется явно описывать колонки источника.
Рассмотрим, как это сделать программно через объект ОписаниеВременнойТаблицыСхемыЗапроса:
// Получаем объект описания из созданного источника
ОписаниеТаблицы = Источник.Источник;
// Добавляем колонки с указанием их типов (необязательно, но полезно для типизации)
НоваяКолонка = ОписаниеТаблицы.Колонки.Добавить("Родитель");
НоваяКолонка = ОписаниеТаблицы.Колонки.Добавить("Правило");
Важный момент: если в имени таблицы-параметра используется амперсанд (&), его необходимо указывать при добавлении источника. Если же вы работаете с временной таблицей, которая уже была создана в МенеджерВременныхТаблиц ранее, амперсанд не используется, но тип источника остается тем же — ОписаниеВременнойТаблицыСхемыЗапроса.
Теперь, когда мы поместили данные во временную таблицу в первом пакете, разберем по шагам, как обратиться к ней во втором пакете. Обратите внимание: во втором и последующих пакетах эта таблица уже считается «известной» схеме, и её не нужно описывать через ОписаниеВременнойТаблицыСхемыЗапроса.
// Добавляем новый пакет запроса (выборка из созданной ВТ)
Пакет2 = СхемаЗапроса.ПакетЗапросов.Добавить(Тип("ЗапросВыбораСхемыЗапроса"));
Оператор2 = Пакет2.Операторы[0];
// Здесь мы уже можем обращаться к ней просто по имени, как к обычной таблице БД
Источник2 = Оператор2.Источники.Добавить("ТаблицаПравилПервогоУровня");
Оператор2.ВыбираемыеПоля.Добавить("ТаблицаПравилПервогоУровня.Родитель");
Оператор2.ВыбираемыеПоля.Добавить("ТаблицаПравилПервогоУровня.Правило");
// Получаем итоговый текст запроса
ТекстЗапроса = СхемаЗапроса.ПолучитьТекстЗапроса();
При программной работе со схемой следует помнить о нескольких критически важных моментах:
Таблица1). При работе с конструкцией ПОМЕСТИТЬ это может привести к путанице, поэтому всегда явно задавайте Псевдоним для источника и ТаблицаДляПомещения для пакета.УстановитьПараметр) символ & в начале имени обязателен внутри метода Добавить для описания временной таблицы.СхемаЗапроса достаточно ресурсоемок. Если ваша задача сводится к простой замене текста или добавлению одного условия ГДЕ, возможно, эффективнее будет использовать метод СтрЗаменить или построитель запроса. Схема оправдана только при действительно сложной динамике.Мы выяснили, что для добавления внешней таблицы значений в СхемаЗапроса необходимо использовать метод Источники.Добавить с первым параметром Тип("ОписаниеВременнойТаблицыСхемыЗапроса"). Это позволяет избежать ошибок поиска метаданных и корректно использовать параметры-таблицы в пакетных запросах. Помните о важности явного указания колонок и псевдонимов для предотвращения неоднозначностей в тексте итогового запроса.