IE 2017

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

Программирование - Практика программирования

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

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

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

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

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

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

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

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

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

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

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

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

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

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

|ИТОГИ ПО

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

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

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

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

 

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

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

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

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

КонецЦикла;

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

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

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

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

;

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

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

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

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

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

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

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

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

 

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

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

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

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

 

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

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

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

 

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

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

 

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

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

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

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

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

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

КонецЦикла;

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

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

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

 

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

 

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

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

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

 

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

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

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

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

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

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

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

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

См. также

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

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

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

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

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

Или я что-то не понимаю.
alyaev.a.v; monkbest; +2 Ответить 1
8. ValeraS2010 55 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 55 08.12.16 18:13 Сейчас в теме
(9) Рад, что вам пригодился описанный способ, но по вашему вопросу - боюсь ,не смогу помочь. Это решение в моей работе - эпизод, причем достаточно экзотический. Часто подобными упражнениями мне заниматься не приходится и корифеем в этой области я не являюсь. Просто решение показалось мне достаточно необычным, чтобы поместить в статью, и чтобы, возможно ,пригодилось другим (ну хотя бы в качестве начальной идеи). Сейчас углубляться в это у меня нет возможности :(.
11. Seneka7608 7 02.02.17 12:09 Сейчас в теме
(9) Видимо у вас поле "ВнутреннийЗаказ" может иметь тип, не содержащий реквизит "Дата". Без анализа кода точно сказать нельзя.
12. Seneka7608 7 02.02.17 13:11 Сейчас в теме
(11) Прошу прощения, "не содержащий реквизит "ДатаОтгрузки""
13. maxster 1 (maxster545) 08.02.17 11:08 Сейчас в теме
Чума!!!
Реально работает...Спасибо!
14. Алексей Сушенцев (Cyxapb) 17.02.17 23:02 Сейчас в теме
работает!! спасибо.

(9) Разыменование ссылочных полей набора данных объект работает в том случае, если указан тип значения поля набора данных. Поскольку в данном случае набор данных объект создается программно, а его поля "копируются" из исходного набора данных запрос, то типы для ссылочных полей нужно явно указать в исходном наборе данных запрос.
15. uri1978 uri1978 (uri1978) 107 04.04.17 11:20 Сейчас в теме
Добрый день.
Если пользователь настроил отборы в отчете, то при программном получении данных запросом (ТабДанных = Запрос.Выполнить().Выгрузить();), эти отборы не работают? Запросом "выгребаются" все данные, и только после этого отрабатывает отбор?
16. ValeraS2010 55 04.04.17 16:54 Сейчас в теме
(15) Ну да - очевидно так. Конечно, это серьезный недостаток - но как обойти это я не знаю.
17. Александр Полетаев (Alias) 35 14.09.17 14:06 Сейчас в теме
(8) Скажите, эту возможность случайно не выпилили? У меня 8.3.9.1850, я никак не могу воспроизвести работающий вариант.
Создаю отчет, в схему СКД добавляю запрос-набор данных, пишу текст как у Вас указано, и при попытке сохранить выдаётся ошибка

Ошибка получения информации набора данных
по причине:
Ошибка в запросе набора данных
по причине:
{(5, 1)}: Таблица не найдена "тзИнтервалов"
<<?>>тзИнтервалов КАК тзИнтервалов

причём неважно, пишу я & или нет. Хотя конструктор запроса, да, работает...
18. ValeraS2010 55 16.09.17 15:10 Сейчас в теме
Не знаю. У меня релиз 1с -2170. Вообще-то работает. Но при попытке проверить - несколько раз вставлял текст, включал конструктор, сохранял - описанная ошибка пару раз проскакивала, но скорее как промежуточный этап , причем не воспроизводимый регулярно - повторно нажимаешь кнопку и все сохраняется. Какие-то нюансы видимо есть. Точно сказать в чем причина не могу.
19. Александр Полетаев (Alias) 35 18.09.17 15:09 Сейчас в теме
(18) "не воспроизводимый регулярно" -- это я могу понять, у меня вроде бы так же. Ошибка возникает только когда текст запроса изменён (добавлен или удалён символ). После попытки сохранить выскакивает ошибка. Но при повторном сохранении того же текста (т.е. когда символы не добавлялись и не удалялись) ошибки, действительно, нет.
Но не заполняются поля (а значит нельзя настроить вариант отчёта) и при запуске отчёта в Предприятии сразу же выскакивает та самая ошибка "Ошибка в запросе набора данных".
Ладно, не получается, может вернусь к этому вопросу позже. Пока обошёл эту необходимость.
Оставьте свое сообщение