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