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