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

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

В процессе разработки отчетов в системе 1С:Предприятие часто возникает задача сопоставления данных из разных типов регистров. Типичный пример: у нас есть периодический Регистр сведений, где хранится история назначения менеджеров для партнеров, и Регистр накопления, содержащий данные о выручке. Сложность заключается в том, что менеджеры могут меняться несколько раз в течение месяца, и нам нужно точно определить, какая сумма продаж относится к конкретному сотруднику в период его ответственности.

В этой статье мы подробно разберем, как правильно связать эти данные, какие алгоритмы использовать в запросах и как избежать типичных ошибок при работе с временными интервалами.

Метод 1: Формирование интервалов «Дата начала — Дата окончания»

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

Проанализируем алгоритм вычисления интервалов в запросе:

  1. Выбираем все записи из регистра сведений «Менеджеры партнеров».
  2. Для каждой записи находим дату следующей записи по тому же самому партнеру.
  3. Если следующей записи нет, считаем датой окончания «пустую дату» или максимально возможное значение времени (31.12.3999).

Рассмотрим пример кода запроса, который формирует такую таблицу интервалов:


ВЫБРАТЬ
    Т1.Партнер КАК Партнер,
    Т1.Менеджер КАК Менеджер,
    Т1.Период КАК ДатаНачала,
    МИНИМУМ(ЕСТЬNULL(Т2.Период, ДАТАВРЕМЯ(3999, 12, 31))) КАК ДатаОкончания
ПОМЕСТИТЬ ВТ_ПериодыМенеджеров
ИЗ
    РегистрСведений.МенеджерыПартнеров КАК Т1
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МенеджерыПартнеров КАК Т2
        ПО Т1.Партнер = Т2.Партнер
            И Т1.Период < Т2.Период
СГРУППИРОВАТЬ ПО
    Т1.Партнер,
    Т1.Менеджер,
    Т1.Период
;

После подготовки такой временной таблицы мы можем легко соединить её с регистром накопления «Выручка и себестоимость продаж». Условие связи будет выглядеть следующим образом: Продажи.Период МЕЖДУ ВТ_ПериодыМенеджеров.ДатаНачала И ВТ_ПериодыМенеджеров.ДатаОкончания. Обратите внимание, что для исключения двойного учета на границах секунд часто используют условие Продажи.Период >= ВТ_ПериодыМенеджеров.ДатаНачала И Продажи.Период < ВТ_ПериодыМенеджеров.ДатаОкончания.

Метод 2: Создание таблицы «Менеджер на каждый день»

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

Рассмотрим, как это реализовать:

  1. Сначала мы формируем таблицу всех дат (дней) за выбранный период. Это можно сделать с помощью запроса к производственному календарю или виртуальной таблице периодов.
  2. Затем мы соединяем эту таблицу дат с регистром сведений.
  3. Для каждой даты получаем «Срез последних» на этот момент времени.

Этот способ более ресурсозатратный, но он позволяет избежать сложных условий «МЕЖДУ» в соединениях, заменяя их простым равенством по дате начала дня. Это может быть полезно, если вы планируете выводить отчет с детализацией по дням.

Метод 3: Получение актуального менеджера на дату документа

Выясним причину, по которой иногда предыдущие методы не подходят: если в базе данных миллионы записей продаж, построение интервалов для всех партнеров может работать медленно. В таком случае эффективнее использовать подход «от документа к менеджеру».

Проанализируем шаги этого метода:

  1. Выбираем все продажи из регистра накопления во временную таблицу ВТ_Продажи.
  2. Присоединяем к ней регистр сведений менеджеров по условию Регистр.Партнер = ВТ_Продажи.Партнер И Регистр.Период <= ВТ_Продажи.Период.
  3. Группируем результат по каждой строке продажи и находим МАКСИМУМ(Регистр.Период). Это и будет дата назначения того менеджера, который работал в момент совершения сделки.

Пример реализации в запросе:


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

ВЫБРАТЬ
    ВТ_Связь.Документ,
    ВТ_Связь.Сумма,
    Менеджеры.Менеджер
ИЗ
    ВТ_Связь КАК ВТ_Связь
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.МенеджерыПартнеров КАК Менеджеры
        ПО ВТ_Связь.Партнер = Менеджеры.Партнер
            И ВТ_Связь.АктуальныйПериод = Менеджеры.Период

Оптимизация и работа с «пустыми» периодами

При работе с левыми соединениями важно помнить о ситуации, когда менеджер для партнера еще не был назначен (например, первая продажа произошла раньше, чем появилась запись в регистре сведений). В таком случае Менеджер в отчете примет значение NULL.

Рекомендации для повышения производительности:

Подводя итог, можно сказать, что выбор метода зависит от объема данных. Для небольших баз отлично подходит вариант с вычислением интервалов (Метод 1). Для высоконагруженных систем лучше использовать получение менеджера по конкретной дате документа (Метод 3) с обязательным использованием индексов временных таблиц.

← На главную