Как сравнить данные за два периода в одном отчете 1С: текущий период и аналогичный период прошлого года

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

В практике разработки на платформе 1С:Предприятие 8 часто возникает задача проведения сравнительного анализа. Одной из наиболее популярных вариаций является сравнение показателей текущего периода с аналогичным периодом прошлого года (Year-to-Year анализ). Рассмотрим ситуацию, когда данные хранятся в периодическом регистре сведений, и нам необходимо вывести суммы поступлений по контрагентам в формате: Плательщик | Сумма текущая | Сумма прошлого года | Разность.

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

Анализ основной ошибки: Виртуальные таблицы vs Физические таблицы

Разберем типичную ситуацию, в которой часто путаются начинающие разработчики. Если нам нужны данные за интервал (например, с 01.03 по 31.07), использование виртуальной таблицы СрезПоследних является методологической ошибкой. Рассмотрим почему:

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

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

Метод 1: Использование объединения (UNION ALL) и временных таблиц

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

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


// Шаг 1: Получаем данные за прошлый период (минус 1 год)
ВЫБРАТЬ
    Поступления.ЮрЛицо КАК ЮрЛицо,
    Поступления.Сумма КАК СуммаПрошлогоПериода,
    0 КАК СуммаТекущегоПериода
ПОМЕСТИТЬ ВТ_ДанныеВсе
ИЗ
    РегистрСведений.Поступления КАК Поступления
ГДЕ
    Поступления.ДатаДок МЕЖДУ ДОБАВИТЬКДАТЕ(&ОтчНачалоПериода, ГОД, -1) 
    И ДОБАВИТЬКДАТЕ(&ОтчКонецПериода, ГОД, -1)

ОБЪЕДИНИТЬ ВСЕ

// Шаг 2: Добавляем данные за текущий период
ВЫБРАТЬ
    Поступления.ЮрЛицо,
    0,
    Поступления.Сумма
ИЗ
    РегистрСведений.Поступления КАК Поступления
ГДЕ
    Поступления.ДатаДок МЕЖДУ &ОтчНачалоПериода И &ОтчКонецПериода;

////////////////////////////////////////////////////////////////////////////////
// Шаг 3: Группируем результат по контрагентам
ВЫБРАТЬ
    ВТ_ДанныеВсе.ЮрЛицо КАК Плательщик,
    СУММА(ВТ_ДанныеВсе.СуммаПрошлогоПериода) КАК СуммаПрошлогоПериода,
    СУММА(ВТ_ДанныеВсе.СуммаТекущегоПериода) КАК СуммаТекущегоПериода,
    СУММА(ВТ_ДанныеВсе.СуммаТекущегоПериода) - СУММА(ВТ_ДанныеВсе.СуммаПрошлогоПериода) КАК Разность
ИЗ
    ВТ_ДанныеВсе КАК ВТ_ДанныеВсе
СГРУППИРОВАТЬ ПО
    ВТ_ДанныеВсе.ЮрЛицо

Почему мы используем ОБЪЕДИНИТЬ ВСЕ вместо соединения? В данном случае это гарантирует, что мы не потеряем плательщиков, которые были в прошлом году, но отсутствуют в текущем, и наоборот. Использование ЛЕВОЕ СОЕДИНЕНИЕ может отсечь данные прошлого периода, если контрагент перестал платить.

Метод 2: Полное соединение (Full Join) для детального анализа

Если нам необходимо вывести дополнительные реквизиты, которые могут отличаться, или если мы хотим визуально разделить выборки в коде, можно использовать временные таблицы и ПОЛНОЕ СОЕДИНЕНИЕ. Однако, рассмотрим важный нюанс: при полном соединении полей с названиями плательщиков необходимо использовать конструкцию ЕСТЬNULL, чтобы название отобразилось корректно.

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


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

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ЮрЛицо,
    СУММА(Сумма) КАК Сумма
ПОМЕСТИТЬ ТекущийГод
ИЗ
    РегистрСведений.Поступления
ГДЕ
    ДатаДок МЕЖДУ &Начало И &Конец
СГРУППИРОВАТЬ ПО ЮрЛицо;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ЕСТЬNULL(ТекущийГод.ЮрЛицо, ПрошлыйГод.ЮрЛицо) КАК Плательщик,
    ЕСТЬNULL(ПрошлыйГод.Сумма, 0) КАК СуммаПрошлогоГода,
    ЕСТЬNULL(ТекущийГод.Сумма, 0) КАК СуммаТекущая
ИЗ
    ТекущийГод КАК ТекущийГод
        ПОЛНОЕ СОЕДИНЕНИЕ ПрошлыйГод КАК ПрошлыйГод
        ПО ТекущийГод.ЮрЛицо = ПрошлыйГод.ЮрЛицо

Проблема производительности: Индексация и типы данных

Выясним причину, почему такие отчеты могут формироваться долго. В исходной задаче упоминалось, что данные хранятся в типе Строка (ЮрЛицо, ИНН). С точки зрения базы данных, соединение по строковым полям — это ресурсозатратная операция.

Как ускорить выполнение запроса:

Архитектурный совет: Регистр накопления

Проанализируем ситуацию с выбором объекта метаданных. Если ваша задача связана с накоплением сумм (денежные средства, продажи, взаиморасчеты), Регистр сведений — не самый подходящий инструмент. Для этих целей в 1С предусмотрен Регистр накопления.

Преимущества Регистра накопления для анализа периодов:

  1. Виртуальная таблица Обороты: Позволяет мгновенно получать готовую сумму за период без необходимости сканирования всех записей физической таблицы.
  2. Итоги: Система хранит предварительно рассчитанные итоги, что делает отчеты по месяцам и годам практически мгновенными.
  3. Упрощение кода: Вместо сложных группировок в запросе вы просто обращаетесь к таблице РегистрНакопления.Имя.Обороты(&Начало, &Конец).

Реализация через Систему компоновки данных (СКД)

Если отчет строится на СКД, можно избежать ручного прописывания ДОБАВИТЬКДАТЕ в тексте запроса. Мы можем настроить параметры в самой схеме:

1. Создадим два набора данных-запроса (для текущего и прошлого года).
2. В параметрах СКД добавим НачалоПрошлогоПериода и укажем для него выражение: ДобавитьКДате(&НачалоПериода, "Год", -1).
3. В закладке Связи наборов данных свяжем их по полю Контрагент.

Такой подход позволяет системе компоновки данных самой оптимизировать запросы к СУБД и корректно выводить итоговые поля разности через Вычисляемые поля.

Рассмотренные методы позволяют эффективно решать задачу сравнения периодов, обеспечивая при этом точность данных и приемлемую скорость работы системы.

← На главную