Как в СКД отсортировать группировку колонок в порядке элементов списка отбора?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов на системе компоновки данных (СКД) часто возникает задача: вывести измерения (например, в колонках таблицы) строго в том порядке, в котором пользователь заполнил список отбора или параметра. По умолчанию СУБД и СКД сортируют данные либо по алфавиту наименований, либо по коду, либо по внутреннему идентификатору ссылки. Разберем, как управлять сортировкой группировок и задать вывод колонок в соответствии с позицией элементов в списке значений.

Суть проблемы и особенности поведения СКД

Когда мы передаем список значений в условие запроса ГДЕ Объект В (&СписокОбъектов), СУБД воспринимает список как неупорядоченное множество. Порядок добавления строк в пользовательских настройках игнорируется при выборке данных. Кроме того, механизм компоновки данных не позволяет напрямую в схеме обратиться к стандартной коллекции Отбор для вычисления порядкового номера элемента.

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

Способ 1. Использование вычисляемого поля и функции общего модуля

Этот метод является наиболее простым в реализации и не требует сложного переопределения стандартного процесса компоновки в коде модуля отчета. Разберем его по шагам.

  1. Создаем параметр вместо стандартного отбора. На вкладке «Параметры» схемы компоновки данных добавляем параметр, например СписокОбъектов, с типом СписокЗначений. Включаем его в пользовательские настройки. В запросе набора данных прописываем условие фильтрации: ГДЕ Объект В (&СписокОбъектов).
  2. Создаем экспортную функцию в общем модуле. Общий модуль должен быть серверным (флаг «Сервер» или «Внешнее соединение»). Функция принимает ссылку на текущий объект и список значений, после чего возвращает числовой индекс позиции элемента.

Посмотрим на пример реализации функции в общем модуле:


Функция ПолучитьПорядокЭлементаВСписке(Элемент, СписокЗначений) Экспорт
    
    Если Не ЗначениеЗаполнено(Элемент) Или СписокЗначений = Неопределено Тогда
        Возврат 99999;
    КонецЕсли;
    
    ЭлементСписка = СписокЗначений.НайтиПоЗначению(Элемент);
    Если ЭлементСписка <> Неопределено Тогда
        Возврат СписокЗначений.Индекс(ЭлементСписка);
    КонецЕсли;
    
    Возврат 99999;
    
КонецФункции
  1. Добавляем вычисляемое поле. На вкладке «Вычисляемые поля» схемы компоновки добавляем поле ПорядокКолонки. В колонке «Выражение» вызываем нашу функцию, передавая поле группировки и параметр со списком: ИмяОбщегоМодуля.ПолучитьПорядокЭлементаВСписке(Объект, &СписокОбъектов).
  2. Настраиваем сортировку группировки. В настройках варианта отчета переходим к группировке колонок (по полю Объект), открываем вкладку «Сортировка» и добавляем поле ПорядокКолонки с направлением «По возрастанию».

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

Способ 2. Передача порядка через временную таблицу в ПриКомпоновкеРезультата

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

Разберем последовательность действий:

  1. В запросе схемы компоновки данных выполняем ЛЕВОЕ СОЕДИНЕНИЕ с временной таблицей ВТ_ПорядокОбъектов по полю Объект и выбираем числовое поле ВТ_ПорядокОбъектов.НомерСтрокиСписка.
  2. В модуле отчета переопределяем стандартное событие ПриКомпоновкеРезультата.

Посмотрим на пример кода в модуле отчета:


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

Способ 3. Программное формирование структуры колонок

Если в отчете требуется нестандартное чередование (например, конкретное подразделение, затем итог по нему, затем следующее подразделение), можно программно управлять структурой колонок в настройках компоновки. Для этого перед выводом очищаются вложенные группировки колонок таблицы и в цикле по списку значений создаются отдельные группировки с фиксированным отбором по каждому элементу.

Таким образом, для простых отчетов быстрее всего применить вычисляемое поле с функцией общего модуля, а для высоконагруженных отчетов с большим объемом данных предпочтительнее передавать порядок через менеджер временных таблиц в процедуре ПриКомпоновкеРезультата.

← На главную