Как в отчете СКД вывести три склада с максимальными продажами для каждого партнера?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В практике разработки на платформе 1С часто возникает задача формирования различных «рейтингов» внутри группировок. Типичный пример для «1С:Управление торговлей 11» — определить для каждого партнера (контрагента) список из трех складов, с которых он совершил покупки на самые крупные суммы. Сложность здесь заключается не просто в расчете оборотов, а в необходимости ограничить выборку именно тремя записями для каждого отдельного клиента, учитывая возможные совпадения сумм и большой объем данных.

Разберем детально, как решить эту задачу несколькими способами: от простых настроек системы компоновки данных (СКД) до сложных запросов.

Способ 1. Использование штатных настроек группировки СКД

Это самый быстрый и надежный способ, который не требует написания сложного кода. Платформа 1С позволяет ограничивать количество выводимых записей для конкретной группировки.

Проанализируем шаги настройки:

  1. Создадим схему компоновки данных и опишем запрос, который получает продажи в разрезе Партнер, Склад и СуммаПродажи. Оптимально использовать регистр накопления ВыручкаИСебестоимостьПродаж.
  2. На закладке «Настройки» создадим иерархию: Группировка по полю Партнер, а внутри нее — подчиненная группировка по полю Склад.
  3. Выберем подчиненную группировку Склад и перейдем на вкладку «Другие настройки» (внизу окна настроек).
  4. Найдем параметр «Количество записей» и установим значение 3.
  5. Перейдем на вкладку «Сортировка» для этой же группировки (Склад) и добавим поле СуммаПродажи с направлением «Убыв».

Важный нюанс: Чтобы избежать неопределенности при равенстве сумм на разных складах (ситуация «tie-breaking»), обязательно добавим второе поле в сортировку — например, Склад.Наименование. Это гарантирует, что при одинаковых продажах состав «Топ-3» будет стабильным при каждом формировании отчета.

Рассмотрим, что произойдет: СКД сначала сгруппирует данные по партнеру, затем внутри каждого партнера отсортирует склады по убыванию суммы и «отрежет» всё, что идет после третьей строки. Это именно то, что требовалось автору темы.

Способ 2. Реализация задачи в тексте запроса (Коррелированный подзапрос)

Иногда требуется получить эти данные уже на уровне запроса (например, для дальнейших расчетов в коде). В современных версиях платформы 8.3 (начиная с 8.3.16) мы можем использовать оператор ВЫБРАТЬ ПЕРВЫЕ внутри вложенных запросов, которые обращаются к полям внешнего запроса.

Посмотрим на пример реализации такого запроса:


ВЫБРАТЬ
    Продажи.Партнер КАК Партнер,
    Продажи.Склад КАК Склад,
    Продажи.СуммаОборот КАК Сумма
ПОМЕСТИТЬ втОбщиеПродажи
ИЗ
    РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(&НачалоПериода, &КонецПериода) КАК Продажи
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    вт.Партнер,
    вт.Склад,
    вт.Сумма
ИЗ
    втОбщиеПродажи КАК вт
ГДЕ
    вт.Склад В (
        ВЫБРАТЬ ПЕРВЫЕ 3
            влож.Склад
        ИЗ
            втОбщиеПродажи КАК влож
        ГДЕ
            влож.Партнер = вт.Партнер
        УПОРЯДОЧИТЬ ПО
            влож.Сумма УБЫВ,
            влож.Склад.Наименование ПРЕДСТ
    )
УПОРЯДОЧИТЬ ПО
    вт.Партнер,
    вт.Сумма УБЫВ

Проанализируем ситуацию: для каждой строки из таблицы втОбщиеПродажи система выполняет подзапрос, который выбирает список из трех лучших складов именно для текущего партнера. Если текущий склад входит в этот «мини-топ», строка попадает в итоговую выборку. Обратите внимание на УПОРЯДОЧИТЬ ПО влож.Склад.Наименование ПРЕДСТ — это критически важно для корректной обработки одинаковых сумм.

Способ 3. «Лобовое» решение через последовательное исключение максимумов

Если по каким-то причинам использование ВЫБРАТЬ ПЕРВЫЕ в подзапросе невозможно (например, на очень старых версиях платформы или специфических СУБД), применим алгоритм последовательного нахождения максимумов. Рассмотрим логику, предложенную в сообщении 10 форума:

  1. Сначала найдем самый максимальный склад для каждого контрагента и сохраним во временную таблицу втМакс1.
  2. Затем выберем данные по продажам, исключив те склады, которые уже попали в втМакс1. Из этого остатка снова найдем максимум — это будет втМакс2.
  3. Повторим процедуру для третьего склада.
  4. В конце объединим (ОБЪЕДИНИТЬ ВСЕ) результаты из трех таблиц.

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


// Получаем продажи
ВЫБРАТЬ Партнер, Склад, СУММА(Сумма) КАК Сумма
ПОМЕСТИТЬ втВсе
ИЗ ... СГРУППИРОВАТЬ ПО Партнер, Склад;

// Находим первый максимум
ВЫБРАТЬ Партнер, МАКСИМУМ(Сумма) КАК МаксСумма1
ПОМЕСТИТЬ втМаксСумма1 ИЗ втВсе СГРУППИРОВАТЬ ПО Партнер;

ВЫБРАТЬ вт.Партнер, вт.Склад, вт.Сумма
ПОМЕСТИТЬ втСклад1
ИЗ втВсе КАК вт
ВНУТРЕННЕЕ СОЕДИНЕНИЕ втМаксСумма1 КАК м1 ПО вт.Партнер = м1.Партнер И вт.Сумма = м1.МаксСумма1;

// Находим второй максимум, исключая первый склад
ВЫБРАТЬ вт.Партнер, МАКСИМУМ(вт.Сумма) КАК МаксСумма2
ПОМЕСТИТЬ втМаксСумма2
ИЗ втВсе КАК вт
ГДЕ НЕ (вт.Партнер, вт.Склад) В (ВЫБРАТЬ Партнер, Склад ИЗ втСклад1)
СГРУППИРОВАТЬ ПО вт.Партнер;

Этот метод громоздкий, но он позволяет обойти ограничения старых версий движка запросов 1С и дает полный контроль над логикой выбора при дублировании сумм.

Способ 4. Вычисляемые выражения СКД (Функция ПолучитьЧасть)

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

Для ресурса ТопСклады можно использовать выражение:

СоединитьСтроки(ПолучитьЧасть(Упорядочить(ВычислитьВыражениеСГруппировкойМассив("Склад", "Склад", "СуммаПродажи Убыв")), 0, 3), ", ")

Разберем это выражение по шагам:

Резюме

Мы проанализировали ситуацию и выяснили, что задача «Топ-3» имеет множество решений. Если вам нужен просто отчет — используйте параметр «Количество записей» в настройках группировки СКД. Если данные нужны в самом запросе — используйте коррелированный подзапрос с конструкцией ВЫБРАТЬ ПЕРВЫЕ 3. Для вывода в одну строку идеально подходят функции работы с массивами в ресурсах СКД.

При работе в «1С:Управление торговлей 11» всегда помните, что данные о продажах лучше брать из специализированных оборотных регистров, а не из документов, чтобы автоматически учитывать возвраты и корректировки реализации.

← На главную