При разработке отчетов на базе системы компоновки данных (СКД) часто возникает задача: на форме отчета пользователь заполняет или редактирует произвольную таблицу (например, список контрагентов с индивидуальными суммами или лимитами), и эти данные необходимо использовать внутри запроса СКД для соединения с таблицами информационной базы. Разберем особенности платформы, выясним причину возникающих ограничений и подробно рассмотрим рабочие способы реализации этой задачи.
В обычном запросе 1С мы можем передать таблицу значений в качестве параметра и поместить ее во временную таблицу конструкцией ПОМЕСТИТЬ. Однако при стандартной работе СКД прямое указание параметра-таблицы в секции ИЗ &ТаблицаОтбора вызывает ошибку. Запрос схемы компоновки данных компилируется на сервере СУБД относительно объектов метаданных конфигурации, и СКД не умеет автоматически преобразовывать переданную в параметры ТаблицуЗначений во временную таблицу СУБД без программного вмешательства.
Для решения этой проблемы проанализируем три основных подхода: использование менеджера временных таблиц, использование набора данных типа «Объект» и динамическую модификацию текста схемы.
Этот способ является наиболее универсальным, если требуется выполнять сложные соединения, подзапросы и группировки между пользовательской таблицей с формы и реальными таблицами базы данных прямо на уровне СУБД. Мы программно создаем временную таблицу до запуска компоновщика и передаем менеджер временных таблиц в процессор компоновки.
Разберем пошаговый алгоритм настройки:
ВТ_Отбор), предполагая, что она уже существует в контексте выполнения:
ВЫБРАТЬ
ВТ_Отбор.Контрагент КАК Контрагент,
ВТ_Отбор.СуммаОтбора КАК СуммаОтбора
ПОМЕСТИТЬ ВТ_ДанныеФормы
ИЗ
ВТ_Отбор КАК ВТ_Отбор
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ПродажиОбороты.Контрагент КАК Контрагент,
ПродажиОбороты.СуммаОборот КАК СуммаОборот,
ВТ_ДанныеФормы.СуммаОтбора КАК Лимит
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ПродажиОбороты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ДанныеФормы КАК ВТ_ДанныеФормы
ПО ПродажиОбороты.Контрагент = ВТ_ДанныеФормы.Контрагент
ПриКомпоновкеРезультата. Создаем объект МенеджерВременныхТаблиц, формируем временную таблицу с помощью обычного запроса и передаем менеджер в метод инициализации процессора компоновки:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// 1. Инициализируем менеджер временных таблиц
МенеджерВТ = Новый МенеджерВременныхТаблиц;
// 2. Создаем временную таблицу ВТ_Отбор на основе таблицы значений из отчета
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ.Контрагент КАК Контрагент,
| ТЗ.СуммаОтбора КАК СуммаОтбора
|ПОМЕСТИТЬ ВТ_Отбор
|ИЗ
| &ТаблицаОтбора КАК ТЗ";
Запрос.УстановитьПараметр("ТаблицаОтбора", ТаблицаОтбора);
Запрос.Выполнить();
// 3. Выполняем компоновку с передачей Менеджера ВТ
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
// Передаем МенеджерВТ четвертым параметром метода Инициализировать
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина, , МенеджерВТ);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывод(ПроцессорКомпоновки);
КонецПроцедуры
Если данные таблицы формы не требуют сложных многократных подзапросов в теле SQL-запроса к БД, можно воспользоваться штатным механизмом внешних наборов данных СКД.
Рассмотрим порядок действий для этого варианта:
ТаблицаОтбора).Контрагент). СКД выполнит соединение этих двух источников в оперативной памяти в процессе компоновки.ПриКомпоновкеРезультата передаем таблицу через структуру внешних наборов данных:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ТаблицаОтбора", ТаблицаОтбора);
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывод(ПроцессорКомпоновки);
КонецПроцедуры
В ситуациях, когда таблица отбора содержит буквально несколько строк и создание менеджера временных таблиц избыточно, можно программно сформировать блок ВЫБРАТЬ ... ОБЪЕДИНИТЬ ВСЕ перед выполнением отчета.
Посмотрим на пример формирования такого блока:
ТекстВыборки = "";
Индекс = 0;
Для Каждого Стр Из ТаблицаОтбора Цикл
Если Индекс > 0 Тогда
ТекстВыборки = ТекстВыборки + " ОБЪЕДИНИТЬ ВСЕ ";
КонецЕсли;
ТекстВыборки = ТекстВыборки + "ВЫБРАТЬ &Контрагент" + Индекс + " КАК Контрагент, &Лимит" + Индекс + " КАК Лимит";
Индекс = Индекс + 1;
КонецЦикла;
Полученный фрагмент подставляется в текст запроса схемы компоновки вместо маркера-шаблона, а соответствующие параметры заполняются в настройках компоновщика перед выводом.
При использовании временных таблиц и передачи ТаблицыЗначений в запрос критически важно учитывать следующие правила:
КвалификаторыЧисла, КвалификаторыСтроки, ссылки на справочники). Если тип колонки останется нетипизированным (Произвольный), запрос 1С может завершиться ошибкой несовместимости типов при выполнении операций соединения.ИНДЕКСИРОВАТЬ ПО в запросе формирования временной таблицы. Это предотвратит сканирование всей таблицы при выполнении соединений и значительно ускорит формирование отчета.