В практике разработки на платформе 1С:Предприятие 8 часто возникает задача проведения сравнительного анализа. Одной из наиболее популярных вариаций является сравнение показателей текущего периода с аналогичным периодом прошлого года (Year-to-Year анализ). Рассмотрим ситуацию, когда данные хранятся в периодическом регистре сведений, и нам необходимо вывести суммы поступлений по контрагентам в формате: Плательщик | Сумма текущая | Сумма прошлого года | Разность.
В этой статье мы подробно разберем, как правильно составить запрос, почему не всегда подходят виртуальные таблицы и как оптимизировать производительность при больших объемах данных.
Разберем типичную ситуацию, в которой часто путаются начинающие разработчики. Если нам нужны данные за интервал (например, с 01.03 по 31.07), использование виртуальной таблицы СрезПоследних является методологической ошибкой. Рассмотрим почему:
СрезПоследних возвращает только одну актуальную запись на конкретную дату по каждой уникальной комбинации измерений.СрезПоследних покажет только последний, а суммы остальных будут потеряны.Проанализируем ситуацию, когда мы все же работаем с регистром сведений. Для корректного сравнения нам потребуется выбрать данные дважды: за основной период и за смещенный на год назад.
Этот способ считается наиболее надежным с точки зрения читаемости кода и отладки. Мы последовательно выбираем данные в две разные временные таблицы, а затем объединяем их.
Рассмотрим пример запроса, который формирует данные для сравнения:
// Шаг 1: Получаем данные за прошлый период (минус 1 год)
ВЫБРАТЬ
Поступления.ЮрЛицо КАК ЮрЛицо,
Поступления.Сумма КАК СуммаПрошлогоПериода,
0 КАК СуммаТекущегоПериода
ПОМЕСТИТЬ ВТ_ДанныеВсе
ИЗ
РегистрСведений.Поступления КАК Поступления
ГДЕ
Поступления.ДатаДок МЕЖДУ ДОБАВИТЬКДАТЕ(&ОтчНачалоПериода, ГОД, -1)
И ДОБАВИТЬКДАТЕ(&ОтчКонецПериода, ГОД, -1)
ОБЪЕДИНИТЬ ВСЕ
// Шаг 2: Добавляем данные за текущий период
ВЫБРАТЬ
Поступления.ЮрЛицо,
0,
Поступления.Сумма
ИЗ
РегистрСведений.Поступления КАК Поступления
ГДЕ
Поступления.ДатаДок МЕЖДУ &ОтчНачалоПериода И &ОтчКонецПериода;
////////////////////////////////////////////////////////////////////////////////
// Шаг 3: Группируем результат по контрагентам
ВЫБРАТЬ
ВТ_ДанныеВсе.ЮрЛицо КАК Плательщик,
СУММА(ВТ_ДанныеВсе.СуммаПрошлогоПериода) КАК СуммаПрошлогоПериода,
СУММА(ВТ_ДанныеВсе.СуммаТекущегоПериода) КАК СуммаТекущегоПериода,
СУММА(ВТ_ДанныеВсе.СуммаТекущегоПериода) - СУММА(ВТ_ДанныеВсе.СуммаПрошлогоПериода) КАК Разность
ИЗ
ВТ_ДанныеВсе КАК ВТ_ДанныеВсе
СГРУППИРОВАТЬ ПО
ВТ_ДанныеВсе.ЮрЛицо
Почему мы используем ОБЪЕДИНИТЬ ВСЕ вместо соединения? В данном случае это гарантирует, что мы не потеряем плательщиков, которые были в прошлом году, но отсутствуют в текущем, и наоборот. Использование ЛЕВОЕ СОЕДИНЕНИЕ может отсечь данные прошлого периода, если контрагент перестал платить.
Если нам необходимо вывести дополнительные реквизиты, которые могут отличаться, или если мы хотим визуально разделить выборки в коде, можно использовать временные таблицы и ПОЛНОЕ СОЕДИНЕНИЕ. Однако, рассмотрим важный нюанс: при полном соединении полей с названиями плательщиков необходимо использовать конструкцию ЕСТЬNULL, чтобы название отобразилось корректно.
Разберем пример реализации:
ВЫБРАТЬ
ЮрЛицо,
СУММА(Сумма) КАК Сумма
ПОМЕСТИТЬ ПрошлыйГод
ИЗ
РегистрСведений.Поступления
ГДЕ
ДатаДок МЕЖДУ ДОБАВИТЬКДАТЕ(&Начало, ГОД, -1) И ДОБАВИТЬКДАТЕ(&Конец, ГОД, -1)
СГРУППИРОВАТЬ ПО ЮрЛицо;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ЮрЛицо,
СУММА(Сумма) КАК Сумма
ПОМЕСТИТЬ ТекущийГод
ИЗ
РегистрСведений.Поступления
ГДЕ
ДатаДок МЕЖДУ &Начало И &Конец
СГРУППИРОВАТЬ ПО ЮрЛицо;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ЕСТЬNULL(ТекущийГод.ЮрЛицо, ПрошлыйГод.ЮрЛицо) КАК Плательщик,
ЕСТЬNULL(ПрошлыйГод.Сумма, 0) КАК СуммаПрошлогоГода,
ЕСТЬNULL(ТекущийГод.Сумма, 0) КАК СуммаТекущая
ИЗ
ТекущийГод КАК ТекущийГод
ПОЛНОЕ СОЕДИНЕНИЕ ПрошлыйГод КАК ПрошлыйГод
ПО ТекущийГод.ЮрЛицо = ПрошлыйГод.ЮрЛицо
Выясним причину, почему такие отчеты могут формироваться долго. В исходной задаче упоминалось, что данные хранятся в типе Строка (ЮрЛицо, ИНН). С точки зрения базы данных, соединение по строковым полям — это ресурсозатратная операция.
Как ускорить выполнение запроса:
ЮрЛицо, убедитесь, что в свойствах реквизита или измерения регистра установлено свойство Индексировать.СправочникСсылка.Контрагенты), а не строковые названия. Сравнение ссылок (идентификаторов GUID) происходит на порядок быстрее, чем сравнение строк.СрезПоследних, всегда передавайте дату среза в первый параметр. Пустая дата заставляет систему искать актуальную запись на текущий момент, что не всегда эффективно в цикле или сложных соединениях.Проанализируем ситуацию с выбором объекта метаданных. Если ваша задача связана с накоплением сумм (денежные средства, продажи, взаиморасчеты), Регистр сведений — не самый подходящий инструмент. Для этих целей в 1С предусмотрен Регистр накопления.
Преимущества Регистра накопления для анализа периодов:
РегистрНакопления.Имя.Обороты(&Начало, &Конец).Если отчет строится на СКД, можно избежать ручного прописывания ДОБАВИТЬКДАТЕ в тексте запроса. Мы можем настроить параметры в самой схеме:
1. Создадим два набора данных-запроса (для текущего и прошлого года).
2. В параметрах СКД добавим НачалоПрошлогоПериода и укажем для него выражение: ДобавитьКДате(&НачалоПериода, "Год", -1).
3. В закладке Связи наборов данных свяжем их по полю Контрагент.
Такой подход позволяет системе компоновки данных самой оптимизировать запросы к СУБД и корректно выводить итоговые поля разности через Вычисляемые поля.
Рассмотренные методы позволяют эффективно решать задачу сравнения периодов, обеспечивая при этом точность данных и приемлемую скорость работы системы.