Как выбрать 10 самых крупных сделок для каждого контрагента в запросе 1С?

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

В процессе разработки отчетов в системе 1С часто возникает задача «Top N в группах». Например, нам необходимо вывести не просто список всех документов, а выбрать только 10 самых крупных сделок для каждого контрагента. Поскольку в языке запросов 1С отсутствуют оконные функции (такие как ROW_NUMBER()), мы должны воспользоваться альтернативными методами. Рассмотрим их подробно.

Метод 1: Использование коррелированного подзапроса

Этот способ является наиболее предпочтительным с точки зрения читаемости кода и производительности на средних объемах данных. Мы используем условие ГДЕ Ссылка В (...), чтобы для каждого контрагента из внешнего запроса вычислить топ-10 документов во внутреннем подзапросе.

Рассмотрим реализацию:


ВЫБРАТЬ
    Сделки.Контрагент,
    Сделки.Ссылка,
    Сделки.СуммаРуб
ИЗ
    Документ.Сделка КАК Сделки
ГДЕ
    Сделки.Ссылка В (
        ВЫБРАТЬ ПЕРВЫЕ 10
            Сделки1.Ссылка
        ИЗ
            Документ.Сделка КАК Сделки1
        ГДЕ
            Сделки1.Контрагент = Сделки.Контрагент
        УПОРЯДОЧИТЬ ПО
            Сделки1.СуммаРуб УБЫВ
    )
УПОРЯДОЧИТЬ ПО
    Сделки.Контрагент,
    Сделки.СуммаРуб УБЫВ

Преимущества этого метода:

  1. Высокая наглядность кода.
  2. Корректная работа с итоговой выборкой (мы получаем именно 10 записей на каждого контрагента, а не 10 всего).
  3. Оптимальное использование ресурсов движка 1С для большинства типовых задач.

Метод 2: Метод самосоединения (через счетчик записей)

Этот метод основан на логическом вычислении «порядкового номера» сделки. Мы соединяем таблицу документов саму с собой по условию: «Контрагент совпадает, а сумма второй сделки больше или равна сумме первой». Это позволяет понять, какое место занимает текущая сделка в списке всех сделок конкретного контрагента.

Разберем этапы реализации:

  1. Сначала выгружаем данные во ВременнуюТаблицу для упрощения обработки.
  2. Производим ЛЕВОЕ СОЕДИНЕНИЕ временной таблицы с самой собой по условию совпадения контрагента и неравенства сумм (или дат/ссылок для уникальности).
  3. Группируем результат, подсчитывая количество таких записей, и отбираем те, где количество не превышает 10.

Пример логики соединения:


ВЫБРАТЬ
    ЛеваяТаблица.Контрагент,
    ЛеваяТаблица.Ссылка,
    ЛеваяТаблица.СуммаРуб
ИЗ
    ВТ_Сделки КАК ЛеваяТаблица
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Сделки КАК ПраваяТаблица
        ПО ЛеваяТаблица.Контрагент = ПраваяТаблица.Контрагент
        И ЛеваяТаблица.СуммаРуб <= ПраваяТаблица.СуммаРуб
ГРУППИРОВАТЬ ПО
    ЛеваяТаблица.Контрагент,
    ЛеваяТаблица.Ссылка,
    ЛеваяТаблица.СуммаРуб
ИМЕЮЩИЕ
    КОЛИЧЕСТВО(ПраваяТаблица.Ссылка) <= 10
УПОРЯДОЧИТЬ ПО
    ЛеваяТаблица.Контрагент,
    ЛеваяТаблица.СуммаРуб УБЫВ

Важные рекомендации по оптимизации

При работе с большими объемами данных (сотни тысяч или миллионы документов) следует учитывать несколько факторов:

  1. Уникальность сумм: Если сделки имеют одинаковую сумму, СУММА(СуммаРуб) может привести к попаданию лишних записей в топ-10. Для точной сортировки всегда добавляйте второе поле, например, МоментВремени или Ссылка.
  2. Производительность: Самосоединение работает по алгоритму с квадратичной сложностью. Если система работает медленно, лучше выгрузить все сделки по контрагентам в ТаблицуЗначений и отсортировать их средствами самого языка 1С (метод Сортировать() и обход цикла с счетчиком). Это часто оказывается быстрее, чем сложные запросы к базе данных.
  3. Индексация: Если вы используете временные таблицы, обязательно указывайте ИНДЕКСИРОВАТЬ ПО для полей, участвующих в соединении (в нашем случае — Контрагент), чтобы ускорить работу запроса.

Надеемся, что эти способы помогут вам успешно решить поставленную задачу и сделать отчеты более информативными!

← На главную