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

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

При анализе данных часто возникает задача определить временные интервалы между операциями одного и того же контрагента. Например, нужно понять, как часто партнер совершает закупки: через 5 дней, через 10 или через месяц. В языке запросов 1С это не самая тривиальная задача, так как записи в базе данных хранятся независимо друг от друга, и «соседние» строки таблицы не имеют прямой связи. Рассмотрим несколько эффективных способов решения этой задачи, начиная от классических соединений и заканчивая современными инструментами платформы.

Метод 1. Соединение таблицы самой с собой (Self-join)

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

Шаг 1. Подготовка данных

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


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

Шаг 2. Поиск следующей даты

Теперь мы соединяем временную таблицу ВТ_Данные саму с собой. Условие соединения должно быть таким: тот же партнер, но дата во второй таблице строго больше, чем в первой. Чтобы найти именно ближайшую следующую дату, мы используем группировку и функцию МИНИМУМ.


ВЫБРАТЬ
    Т1.Партнер КАК Партнер,
    Т1.ДатаДок КАК ДатаТекущая,
    МИНИМУМ(Т2.ДатаДок) КАК ДатаСледующая
ПОМЕСТИТЬ ВТ_СоседниеДаты
ИЗ
    ВТ_Данные КАК Т1
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Данные КАК Т2
        ПО Т1.Партнер = Т2.Партнер
            И Т1.ДатаДок < Т2.ДатаДок
СГРУППИРОВАТЬ ПО
    Т1.Партнер,
    Т1.ДатаДок,
    Т1.Ссылка
;

Шаг 3. Финальный расчет разницы

Проанализируем полученную таблицу. Теперь в каждой строке у нас есть текущая дата документа и дата следующего за ним документа. Нам остается только применить функцию РАЗНОСТЬДАТ.


ВЫБРАТЬ
    Т.Партнер,
    Т.ДатаТекущая,
    Т.ДатаСледующая,
    РАЗНОСТЬДАТ(Т.ДатаТекущая, Т.ДатаСледующая, ДЕНЬ) КАК ИнтервалВДнях
ИЗ
    ВТ_СоседниеДаты КАК Т
ГДЕ
    Т.ДатаСледующая ЕСТЬ НЕ NULL

Метод 2. Решение проблемы одинаковых дат

В реальной базе возможна ситуация, когда у одного партнера есть два документа с абсолютно одинаковым временем. В этом случае условие Т1.ДатаДок < Т2.ДатаДок сработает некорректно (пропустит документы). Чтобы избежать этого, проанализируем ситуацию и добавим в условие соединения уникальный идентификатор (ссылку).

Изменим условие соединения на следующее:


ПО Т1.Партнер = Т2.Партнер 
    И (Т1.ДатаДок < Т2.ДатаДок ИЛИ (Т1.ДатаДок = Т2.ДатаДок И Т1.Ссылка < Т2.Ссылка))

Такой подход гарантирует, что система всегда найдет «следующий» документ, даже если время совпадает до секунды.

Метод 3. Использование СКД (функция ВычислитьВыражение)

Если ваша задача — вывести эти данные в отчет, то использование сложных соединений в запросе может быть избыточным. Система компоновки данных (СКД) предоставляет мощный механизм ВычислитьВыражение, который работает гораздо быстрее на больших объемах данных.

Разберем, как настроить расчет в СКД:

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

Этот метод позволяет избежать квадратичной сложности запроса, которая возникает при соединении таблицы «самой на себя».

Метод 4. Оконные функции (Платформа 8.3.20+)

В современных версиях платформы 1С реализована поддержка оконных функций прямо в языке запросов. Это самый прогрессивный метод. Мы можем использовать функцию LAG (или её эквивалент через синтаксис окон), чтобы получить значение из предыдущей строки.

Пример логики запроса с оконной функцией (доступно в новых релизах):


ВЫБРАТЬ
    Продажи.Партнер,
    Продажи.Период,
    РАЗНОСТЬДАТ(
        ВЫЧИСЛИТЬВЫРАЖЕНИЕ("Период", "ПАРТНЕР", "ПЕРИОД ВОЗРАСТАНИИ", "1 ПРЕДЫДУЩАЯ"), 
        Продажи.Период, 
        ДЕНЬ
    ) КАК Интервал
ИЗ
    РегистрНакопления.Продажи КАК Продажи

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

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

Выбор конкретного метода зависит от версии вашей платформы и объема данных. Для небольших таблиц отлично подойдет Метод 1. Если вы строите отчет — используйте возможности СКД. Для высоконагруженных систем на актуальных версиях платформы отдавайте предпочтение оконным функциям.

← На главную