При разработке отчетов в системе 1С:Предприятие часто возникает задача анализа динамики данных. Нам может потребоваться вычислить разницу между показателями текущей строки и предыдущей, рассчитать отклонение или вывести накопительный итог (сальдо). В зависимости от того, используете ли вы Систему компоновки данных (СКД) или выводите отчет программно с помощью собственного макета, подходы будут различаться. Рассмотрим детально оба варианта.
Если ваш отчет строится на СКД, наиболее эффективным и правильным методом является использование встроенного языка выражений компоновки данных. Для этого нам не нужно писать программный код в модулях, достаточно настроить поле на вкладке «Ресурсы».
Рассмотрим ситуацию, когда нам нужно получить разность цен или сумм. Основным инструментом здесь выступает функция ВычислитьВыражение. Разберем ее синтаксис для нашей задачи:
Формула для ресурса:
Сумма(Цена) - ЕстьNull(ВычислитьВыражение("Сумма(Цена)", , , "Предыдущая", "Предыдущая"), 0)
Проанализируем параметры, которые мы использовали в этой функции:
"Сумма(Цена)" — это то агрегатное значение, которое мы хотим получить из другой строки."Предыдущая" для обоих значений. Это критически важный момент — именно так мы сообщаем системе, что хотим взять значение ровно из одной предыдущей строки относительно текущей.Важный нюанс: В самой первой строке отчета «предыдущей» строки не существует. В этом случае функция вернет NULL. Чтобы результат вычитания не превратился в пустоту, мы обязательно используем функцию ЕстьNull, заменяя неопределенное значение нулем.
Иногда логика отчета настолько сложна (например, график лизинговых платежей с распределением оплат), что стандартных механизмов СКД может быть недостаточно, и разработчик прибегает к программному выводу через ТабличныйДокумент и Макет. В этом случае расчет разницы ложится на плечи программиста в цикле обхода данных.
Разберем алгоритм на примере обработки ТаблицыЗначений. Основная идея заключается в использовании временной переменной-буфера, которая будет хранить значение текущей строки для использования в следующей итерации цикла.
Проанализируем пример кода:
// Инициализируем переменные перед началом цикла
ПеременнаяПредыдущегоЗначения = 0;
ИтоговаяРазность = 0;
Для Каждого СтрокаДанных Из ТзДанные Цикл
// Если это не первая итерация, мы можем вычислить разницу
Если ПеременнаяПредыдущегоЗначения <> 0 Тогда
ТекущееОтклонение = СтрокаДанных.Сумма - ПеременнаяПредыдущегоЗначения;
Иначе
ТекущееОтклонение = 0; // Для первой строки разница обычно не считается
КонецЕсли;
// Заполняем параметры макета
ОбластьСтрока.Параметры.Заполнить(СтрокаДанных);
ОбластьСтрока.Параметры.Отклонение = ТекущееОтклонение;
// Выводим строку в результирующий документ
ДокументРезультат.Вывести(ОбластьСтрока);
// Сохраняем текущее значение как "предыдущее" для следующего шага цикла
ПеременнаяПредыдущегоЗначения = СтрокаДанных.Сумма;
КонецЦикла;
Выясним причину, почему этот метод надежен: он позволяет полностью контролировать условия расчета. Например, вы можете обнулять «предыдущее значение» при смене определенной группировки (например, при переходе к новому контрагенту), чего иногда сложно добиться в простом запросе.
Часто под задачей «вычесть из предыдущей» подразумевается вычисление остатка или сальдо нарастающим итогом. Рассмотрим, как это реализовать в СКД более изящно, чем простое вычитание соседних строк.
Если нам нужно посчитать разницу между всеми приходами и расходами с самого начала отчета до текущей строки, мы используем область "Первая":
ВычислитьВыражение("Сумма(СуммаОплаты) - Сумма(СуммаПлатежа)", , , "Первая", "Текущая")
В этом выражении система суммирует все значения от самой первой строки группировки до текущей включительно. Это идеальный способ для формирования колонок типа «Остаток» в ведомостях взаиморасчетов.
При работе с вычислениями между строками следует учитывать несколько профессиональных советов:
Дата или Период). Без этого результат будет непредсказуемым.ВычислитьВыражение работает достаточно быстро, но на экстремально больших объемах данных (сотни тысяч строк) может вызывать замедление. В таких случаях стоит рассмотреть возможность предварительного расчета разниц во временных таблицах запроса с использованием АВТОНОМЕРЗАПИСИ() и соединения таблицы самой с собой по условию Т1.Номер = Т2.Номер + 1.Подводя итог, можно сказать, что для большинства стандартных отчетов 1С функции ВычислитьВыражение в СКД более чем достаточно. Она лаконична, понятна и легко поддерживается при изменении структуры отчета. Программный же перебор строк в цикле стоит оставлять для тех случаев, когда вы полностью отказываетесь от механизмов компоновки в пользу ручного управления выводом каждой ячейки.