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