gifts2017

Передача объекта ТаблицаЗначений в СКД в качестве параметра

Опубликовал ValeraS2010 в раздел Программирование - Практика программирования

Передача объекта ТаблицаЗначений в СКД в качестве параметра путем замены набора данных с сохранением механизма пользовательских настроек и отборов.

      Всем привет. Недавно возникла необходимость передать таблицу значений в СКД в качестве параметра. Как это сделать для обычного запроса - способ давно известен — создается пакет запросов с временной таблицей, в которую передаются все поля внешней таблицы через параметр. Однако в случае СКД этот трюк не работает. Поиски решения в гугле дали скорее отрицательный результат: подобные вопросы поднимались неоднократно, но решения , которое показалось бы мне простым и удобным так и не удалось найти. Самый близкий к теме подход состоял в том чтобы передавать таблицу в СКД в качестве набора данных типа объект, а затем при необходимости соединять с этим набором наборы-запросы СКД. В таком виде решение не устраивало по следующим причинам:

  1. Нужно вручную расписывать структуру полей набора данных типа объект.

  2. Соединение наборов данных происходит по правилам, несколько отличным от соединения таблиц в запросе и так как пользоваться этим приходится редко, то не хочется тратить время и разбираться в этом, если можно все свести к старым привычным запросам.

      В результате был найден обходной путь. Не знаю — возможно этот велосипед уже кто-то раньше изобрел, но я работающей схемы не встречал , поэтому решил поделиться опытом.

  Теперь собственно «ноу-хау»: Для начала представим таблицу , которую нужно передать в СКД. Пусть это будет, например таблица периодов.

ВыбИнтервал = "ДЕНЬ";

тзИнтервалов = Новый ТаблицаЗначений;

тзИнтервалов.Колонки.Добавить("НачИнтервала", Новый ОписаниеТипов("Дата"));

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ

| НАЧАЛОПЕРИОДА(&НачДата, "+ВыбИнтервал+") КАК НачИнтервала

|УПОРЯДОЧИТЬ ПО

| НачИнтервала

|ИТОГИ ПО

| НачИнтервала ПЕРИОДАМИ("+ВыбИнтервал+", &НачДата, &КонДата)";

//Параметры запроса

Запрос.УстановитьПараметр("НачДата", НачПериода);

Запрос.УстановитьПараметр("КонДата", КонПериода);

 

Выборка = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "НачИнтервала", "ВСЕ");

Пока Выборка.Следующий() Цикл

НоваяСтрока = тзИнтервалов.Добавить();

НоваяСтрока.НачИнтервала = Выборка.НачИнтервала;

КонецЦикла;

//тзИнтервалов.ВыбратьСтроку();

     Теперь возвращаемся в конструктор запросов СКД, где мы ваяем наш большой и сложный запрос. Создаем описание временной таблицы с помощью кнопки.

Сотав полей должен быть аналогичен внешней таблице. В нашем случае это одно поле.

ВЫБРАТЬ
    тзИнтервалов.НачИнтервала КАК ДатаКалендаря
ПОМЕСТИТЬ втИнтервалов
ИЗ
    тзИнтервалов КАК тзИнтервалов

;

////////////////////////////////////////////////////////////////////////////////

Далее строим запрос как обычно. Затем извлекаем текст запроса для построения набора данных типа объект:

СКДНастроек = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");

ТекстЗапроса = СКДНастроек.НаборыДанных.НаборДанных1.Запрос;

Меняем текст запроса так, чтобы первая временная таблица принимала через параметр нашу таблицу значений:

 ТекстЗапроса = СтрЗаменить(ТекстЗапроса,

"тзИнтервалов КАК тзИнтервалов",

"&тзИнтервалов КАК тзИнтервалов");

 

Запрос = Новый Запрос;

Запрос.Текст = ТекстЗапроса;

     Затем формируем отчет програмным способом, при этом подменяя набор данных — вместо набора запроса подставляем эквивалентный набор данных типа объект:

настройкиСКД = СКДНастроек.ВариантыНастроек.Найти("Основной").Настройки;

 

ТабДанных = Запрос.Выполнить().Выгрузить();

ВнешниеНаборыДанных = Новый Структура;

ВнешниеНаборыДанных.Вставить("ТаблицаДанных", ТабДанных);

 

//Макет компоновки

КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;

 

ВнешнийНД = СКДНастроек.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));

ИмяНД = СКДНастроек.НаборыДанных[0].Имя;

ЗаполнитьЗначенияСвойств(ВнешнийНД, СКДНастроек.НаборыДанных.НаборДанных1);

Для каждого ПолеСКД Из СКДНастроек.НаборыДанных[0].Поля Цикл

НовоеПоле = ВнешнийНД.Поля.Добавить(ТипЗнч(ПолеСКД));//(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));

ЗаполнитьЗначенияСвойств(НовоеПоле,ПолеСКД);

КонецЦикла;

СКДНастроек.НаборыДанных.Удалить(СКДНастроек.НаборыДанных[0]);

СКДНастроек.НаборыДанных[0].Имя = ИмяНД;

СКДНастроек.НаборыДанных[0].ИмяОбъекта = "ТаблицаДанных";

 

МакетКомпоновки = КомпоновщикМакета.Выполнить(СКДНастроек,НастройкиСКД,ДанныеРасшифровки );

 

//Компоновка данных

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;

ПроцессорКомпоновки.Инициализировать(МакетКомпоновки,ВнешниеНаборыДанных, ДанныеРасшифровки);

 

//Вывод результата

ДокументРезультат = ЭлементыФормы.Результат;

ДокументРезультат.Очистить();

ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;

ПроцессорВывода.УстановитьДокумент(ДокументРезультат);

ПроцессорВывода.Вывести(ПроцессорКомпоновки);

ДокументРезультат.Показать();

Вот и все. При таком способе сохраняется возможность для пользователя управления настройками отчета. Формирование отчета программным путем тривиально и описано во многих учебниках. Единственный нестандартный момент - подмена набора данных. Весь код можно использовать практически без изменений — только переделка части запроса из сгенерированной конструктором функцией СтрЗаменить — для кажного случая будет своя. Насколько такой метод хорош — это конечно дело вкуса. Просто еще один способ, может быть кому-нибудь будет полезно.

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Игорь Макаренко (Kashemir) 04.09.15 13:02
Решение хорошее, неоднократно к подобному прибегал. Однако не понимаю как оно решает озвученную проблему "Соединение источников данных происходит по правилам, несколько отличным от соединения таблиц в запросе и так как пользоваться этим приходится редко, то не хочется тратить время и разбираться в этом, если можно все свести к старым привычным запросам". От наборов, к которым как известно может применяется только левое соединение, оно никуда не уводит. В то же время проблема типизации колонок внешнего источника не такая уж и проблема :) Затратив меньшие усилия можно набросать обработку по быстрому созданию набора данных внешних на основе переданной таблицы с последующим сохранением данной схемы для возможности использования в ручном режиме.

В моем опыте использование данного подхода мотивировалось необходимостью получить исходные настройки отборов/группировок пользователя в привычном ему виде СКД. После чего отборы использовались уже в программных запросах формирования внешнего источника (к примеру циклическая раскрутка данных дебиторки помесячно на заранее неизвестную глубину). После чего данные сформированного внешнего источника + настройки пользователя использовались для вывода результатов.

2. Anatolii Karasev (KapasMordorov) 04.09.15 13:30
Кажется, что автор путает внешние источники данных и "набор данных - объект" в СКД.
Про "работающую схему не встречал" тоже не понял.
Когда я столкнулся с этой проблемой, нашел в форумах обсуждения еще от 2011г.
Схема обычная: использование в СКД набора данных объект, его программное заполнение и программное выполнение СКД. Структуру полей конечно вручную приходится создавать, но в общем времени разработки отчета это мелочь.
3. Игорь Макаренко (Kashemir) 04.09.15 13:42
(1) Если нужно - можно пример по программному создании набора на основе ТЗ выдрать отсюда http://infostart.ru/public/74068/ В частности, на закладке "Модификация набора записей->Редактирование набора" фильтрация осуществляется средствами отбора схема, сформированной подобным образом.
4. ValeraS2010 04.09.15 17:39
KapasMordorov - Спасибо за коментарий.
//Кажется, что автор путает внешние источники данных и "набор данных - объект" в СКД.
Да, действительно перепутал. Каюсь :)
//Про "работающую схему не встречал" тоже не понял.
Не встречал - значит буквально - не встречал. Это не значит - не существует. Глубокого патентного исследования не проводилось - это правда
5. Андрей Щеглов (Andrefan) 09.09.15 09:32
(4)
Да, действительно перепутал. Каюсь :)

Ну хоть поправил бы статью ради приличия. Зачем людей путать?
6. Ловыгин Антон (wunderland) 10.09.15 16:31
http://infostart.ru/public/118353/ - что-то похожее здесь делал, давно уже. Но изобрел не сам а нашел и допилил, только где - уже не вспомню. Так что, вроде, описанное - не такая уж проблема.
7. Алексей (Khanja) 06.12.16 02:28
Уважаемый автор, а не могли бы вы пояснить на счет создания временной таблицы в СКД. Предоставленый вами код создания ВТ имеет синтаксическую ошибку. "ПОМЕСТИТЬ" стоит после "ИЗ".

Да же, если поставить в правильной последовательности, то конструктор СКД ругается: "Ошибка в запросе набора данных по причине:Таблица не найдена "тзИнтервалов".

Или я что-то не понимаю.
8. ValeraS2010 06.12.16 11:42
(7) Вы правы - есть синтаксическая ошибка :(. Но в правильном варианте у меня все работает (версия 8.3 - может в этом дело?..). Приведенный код должен выглядеть так:

"ВЫБРАТЬ
тзИнтервалов.НачИнтервала КАК ДатаКалендаря
ПОМЕСТИТЬ втИнтервалов
ИЗ
тзИнтервалов КАК тзИнтервалов"



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

Прикрепленные файлы:
9. Иван (user652676_vvvaaannn85) 08.12.16 12:45
Уважаемый автор, спасибо за статью. Я использую указанное вами решение для внесение изменений в таблицу значений, полученную в результате выполнения запроса. Все работает замечательно, за исключением возможности использовать доступ к вложенным полям через точку (на пример: Номенклатура.Артикул, ВнутреннийЗаказ.ДатаОтгрузки). При добавлении такого поля в список выбранных полей оно не отображается, при попытке отфильтровать или сгруппировать по такому полю возникает ошибка:
"Ошибка исполнения отчета
по причине:
Ошибка при выполнении обработчика - 'ПриКомпоновкеРезультата'
по причине:
{ВнешнийОтчет.МойОтчет.МодульОбъекта(103)}: Ошибка при вызове метода контекста (Выполнить)

по причине:
Ошибка компоновки макета
по причине:
Поле не найдено "ВнутреннийЗаказ.ДатаОтгрузки"
"
Отбор и группировку делаю по полям, которые добавлены в список выбранных полей. Поле "ВнутреннийЗаказ" присутствует в запросе.
Версия платформы - 8.3.7.2027, конфигурация - УПП для Украины 1.3.42.2.
Возможно ли сделать так, чтобы можно было использовать вложенные поля?
10. ValeraS2010 08.12.16 18:13
(9) Рад, что вам пригодился описанный способ, но по вашему вопросу - боюсь ,не смогу помочь. Это решение в моей работе - эпизод, причем достаточно экзотический. Часто подобными упражнениями мне заниматься не приходится и корифеем в этой области я не являюсь. Просто решение показалось мне достаточно необычным, чтобы поместить в статью, и чтобы, возможно ,пригодилось другим (ну хотя бы в качестве начальной идеи). Сейчас углубляться в это у меня нет возможности :(.