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