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