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