При разработке отчетов в системе компоновки данных (СКД) часто возникает задача сортировки строк (например, контрагентов или номенклатуры) не по алфавиту, а по значениям ресурсов в динамических колонках (например, по выручке в разрезе месяцев). Стандартная настройка сортировки в группировке строк часто не дает нужного результата в кросс-таблицах, так как порядок строк определяется один раз для всей таблицы, а колонки периодов строятся динамически.
В этой статье мы подробно разберем, почему возникает эта сложность, и рассмотрим несколько эффективных способов решения задачи: от модификации запроса до использования вычисляемых полей и математических формул упорядочивания.
Давайте проанализируем ситуацию. В классической матрице (кросс-таблице) СКД у нас есть группировка строк (например, Партнеры) и группировка колонок (например, Месяцы). Система сначала определяет порядок вывода строк, а затем распределяет данные по колонкам. Мы не можем сделать так, чтобы в колонке "Январь" партнеры шли в одном порядке, а в "Феврале" — в другом, так как это нарушило бы структуру строки таблицы.
Следовательно, наша задача — создать единый индекс приоритета для каждой строки, который будет учитывать продажи во всех месяцах последовательно. Рассмотрим, как это реализовать.
Если количество периодов заранее известно (например, отчет всегда строится за квартал или год), мы можем подготовить специальные поля для сортировки непосредственно в тексте запроса. Разберем этот пример на основе выручки по месяцам.
Добавим в запрос выборку сумм по конкретным условиям:
ВЫБРАТЬ
Т.Период КАК Период,
Т.Контрагент КАК Контрагент,
Т.СтоимостьОборот КАК СтоимостьОборот,
ВЫБОР КОГДА МЕСЯЦ(Т.Период) = 1 ТОГДА Т.СтоимостьОборот ИНАЧЕ 0 КОНЕЦ КАК СуммаМесяц1,
ВЫБОР КОГДА МЕСЯЦ(Т.Период) = 2 ТОГДА Т.СтоимостьОборот ИНАЧЕ 0 КОНЕЦ КАК СуммаМесяц2,
ВЫБОР КОГДА МЕСЯЦ(Т.Период) = 3 ТОГДА Т.СтоимостьОборот ИНАЧЕ 0 КОНЕЦ КАК СуммаМесяц3
ИЗ
РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(&НачалоПериода, &КонецПериода, Месяц, ) КАК Т
После этого в СКД необходимо выполнить следующие действия:
СуммаМесяц1, СуммаМесяц2 и т.д. ресурсами с функцией СУММА.Контрагент), перейти на закладку Сортировка.СуммаМесяц1 (по убыванию), затем СуммаМесяц2 и так далее.В этом случае система сначала выстроит партнеров по продажам января. Если у нескольких партнеров продажи в январе одинаковы (или равны нулю), они будут отсортированы по продажам февраля.
Первый способ неудобен, если периодов много или они постоянно меняются. Рассмотрим более универсальный метод — создание "синтетического" поля упорядочивания. Суть метода заключается в том, чтобы присвоить каждому факту продажи "вес", зависящий от даты.
В запросе или в вычисляемых полях СКД мы можем создать формулу, где целая часть числа будет отвечать за период, а дробная — за сумму. Проанализируем пример выражения:
РАЗНОСТЬДАТ(ВыручкаИСебестоимостьПродажОбороты.Период, &КонецПериода, МЕСЯЦ) +
СУММА(ЕСТЬNULL(ВыручкаИСебестоимостьПродажОбороты.СуммаВыручкиОборот, 0)) / 1000000000
Рассмотрим, как это работает по шагам:
РАЗНОСТЬДАТ вычисляет удаленность месяца от конца периода. Чем раньше был месяц, тем больше будет целое число.МАКСИМУМ.Важный момент: использование ЕСТЬNULL критически важно, чтобы отсутствие данных не привело к пустому результату всего выражения, что нарушит логику сортировки.
Если суммы выручки очень велики и дробная часть может привести к потере точности или ошибкам переполнения, можно использовать строковое представление. Этот метод считается наиболее надежным для обеспечения универсальной сортировки.
Создадим вычисляемое поле ПолеУпорядочивания со следующим выражением:
ВЫБОР
КОГДА ЕСТЬNULL(Сумма, 0) <> 0
ТОГДА Формат(Период, "ДФ=yyyyMMdd")
ИНАЧЕ "00000000"
КОНЕЦ + Формат(Сумма, "ЧЦ=20; ЧВН=; ЧГ=0")
Разберем логику этого решения:
ЧВН= (число с ведущими нулями) крайне важен: он гарантирует, что сумма 100 будет стоять выше, чем 50, так как строки будут иметь вид "00000000000000000100" и "00000000000000000050".МАКСИМУМ.Такой подход позволяет системе однозначно определить приоритет каждой строки на основе самого раннего или самого крупного вхождения суммы в периоде.
Если логика сортировки слишком сложна для языка выражений СКД (например, нужно учитывать нелинейные веса или внешние данные), рассмотрим вариант с программным формированием результата.
Посмотрим на алгоритм реализации:
ТаблицаЗначений.ИндексСортировки и заполняем её по любому сложному алгоритму на языке 1С.ТаблицаЗначений.Сортировать().В настройках СКД в этом случае достаточно просто оставить сортировку "Без упорядочивания" или по полю ИндексСортировки, так как данные уже придут в нужном порядке.
Проанализируем еще несколько важных технических моментов, которые помогут избежать ошибок:
1. Настройка "Выражение упорядочивания":
В СКД на закладке "Наборы данных" у каждого поля (например, у Партнера) есть свойство "Выражение упорядочивания". Вместо того чтобы добавлять в отчет лишние колонки для сортировки, вы можете прямо там прописать логику (например, ссылку на ваше вычисляемое поле). Это позволит пользователю видеть в отчете только названия партнеров, в то время как система "под капотом" будет знать, как их правильно выстроить.
2. Обработка иерархии:
Если вы используете иерархические группировки, помните, что стандартная сортировка по ресурсу может "развалить" иерархию. В настройках группировки всегда проверяйте тип сортировки. Для корректной работы часто требуется указывать сортировку внутри групп, чтобы родители всегда оставались над своими дочерними элементами, независимо от их суммарной выручки.
3. Использование "Значений группировок" в настройках:
В последних версиях платформы 8.3 в окне настроек сортировки для группировки строк можно нажать кнопку выбора и указать конкретное значение из группировки колонок. Например, выбрать "Выручка" и в параметрах указать конкретную дату. Это работает, если вы хотите жестко отсортировать весь отчет только по одному конкретному месяцу (например, текущему).
Выбор конкретного метода зависит от требований к гибкости отчета. Для простых случаев достаточно математического индекса, а для сложных корпоративных отчетов с плавающим периодом лучше использовать строковое форматирование или программную подготовку данных.