При разработке отчетов на системе компоновки данных (СКД) в 1С часто возникает задача, когда показатели в отчете выводятся в виде строк (вертикальная структура), и один из этих показателей должен рассчитываться на основе значений других показателей. Например, у нас есть три показателя: п1, п2 и п3. Значения п1 и п2 берутся напрямую из базы данных, а п3 должен рассчитываться как п1 / п2 для каждого конкретного подразделения.
Сложность заключается в том, что СКД при расчете ресурса для строки с показателем п3 оперирует только тем контекстом (теми детальными записями), который относится к этой строке. В детальных записях для п3 значения других показателей отсутствуют, что приводит к невозможности стандартного расчета через простую формулу ресурса. В этой статье мы подробно разберем несколько эффективных способов решения этой проблемы.
Проанализируем ситуацию. Допустим, наш источник данных возвращает таблицу следующего вида:
Если в настройках СКД мы создадим группировку по полю Показатель, то при расчете ресурса в строке п3 система будет видеть только запись Отдел продаж | п3 | 0. Любая попытка написать формулу вида Сумма(Выбор Когда Показатель = "п1" Тогда Значение Иначе 0 Конец) вернет 0, потому что в контексте строки п3 записей с показателем п1 просто нет. Это приведет к ошибке деления на ноль или неверным результатам.
Рассмотрим по шагам решения, которые позволяют обойти это ограничение.
Это наиболее изящный способ, реализованный средствами самой СКД. Функция ВычислитьВыражение позволяет вычислять значения по другим группировкам, выходя за рамки текущего контекста строки. Нам понадобятся расширенные параметры этой функции, а именно шестой параметр, отвечающий за отбор.
Перейдем на вкладку Ресурсы в схеме компоновки данных. Для поля Значение напишем следующую формулу ресурса:
Выбор
Когда Показатель = "п3" Тогда
ВычислитьВыражение("Сумма(Значение)", "Подразделение", , "Первая", "Последняя", "Показатель = ""п1""") /
Выбор
Когда ВычислитьВыражение("Сумма(Значение)", "Подразделение", , "Первая", "Последняя", "Показатель = ""п2""") = 0 Тогда 1
Иначе ВычислитьВыражение("Сумма(Значение)", "Подразделение", , "Первая", "Последняя", "Показатель = ""п2""")
Конец
Иначе Сумма(Значение)
Конец
Разберем подробнее, как работает эта конструкция:
"Сумма(Значение)" указывает, какое именно выражение мы хотим рассчитать."Подразделение" задает группировку, в рамках которой производится расчет. Это гарантирует, что мы не смешаем данные разных подразделений."Первая" и "Последняя" определяют границы поиска записей внутри этой группировки."Показатель = ""п1""" выполняет отбор. Система находит строки текущего подразделения, где показатель равен п1, и суммирует их значения, игнорируя то, что текущая строка отчета строится для п3.п2 с проверкой на деление на ноль, чтобы избежать критических ошибок при выводе отчета.Если структура показателей фиксирована, самым надежным и производительным решением будет изменение структуры данных еще на этапе их получения. Вместо вертикальной таблицы показателей мы можем получить горизонтальную.
Проанализируем, как должен выглядеть запрос. Нам нужно преобразовать строки в колонки, чтобы каждая запись содержала все показатели одновременно:
ВЫБРАТЬ
ИсходныеДанные.Подразделение КАК Подразделение,
ВЫРАЗИТЬ(ВЫБОР КОГДА ИсходныеДанные.Показатель = "п1" ТОГДА ИсходныеДанные.Значение ИНАЧЕ 0 КОНЕЦ КАК ЧИСЛО(15,2)) КАК Значение_п1,
ВЫРАЗИТЬ(ВЫБОР КОГДА ИсходныеДанные.Показатель = "п2" ТОГДА ИсходныеДанные.Значение ИНАЧЕ 0 КОНЕЦ КАК ЧИСЛО(15,2)) КАК Значение_п2
ПОМЕСТИТЬ ВТ_Свернутая
ИЗ
&ТаблицаИсточника КАК ИсходныеДанные
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_Свернутая.Подразделение КАК Подразделение,
СУММА(ВТ_Свернутая.Значение_п1) КАК Значение_п1,
СУММА(ВТ_Свернутая.Значение_п2) КАК Значение_п2
ИЗ
ВТ_Свернутая КАК ВТ_Свернутая
ГРУППИРОВАТЬ ПО
ВТ_Свернутая.Подразделение
После получения такой таблицы в СКД мы можем пойти двумя путями:
Значение_п3 с формулой Выбор Когда Значение_п2 = 0 Тогда 0 Иначе Значение_п1 / Значение_п2 Конец.В случаях, когда логика расчета показателя п3 выходит за рамки простого деления (например, требуются сложные финансовые алгоритмы, округления или многоступенчатые проверки), формулы СКД становятся громоздкими и нечитаемыми. Тогда целесообразно вынести расчет в экспортную функцию общего модуля.
Создадим в конфигураторе неглобальный общий модуль (например, ОтчетыСервер) и напишем в нем функцию:
Функция РассчитатьПоказательЭффективности(Значение1, Значение2) Экспорт
Если Значение2 = 0 Тогда
Возврат 0;
КонецЕсли;
// Здесь может быть любая сложная математическая логика
Результат = Значение1 / Значение2;
Возврат Окр(Результат, 2);
КонецФункции
Теперь в схеме компоновки данных на вкладке Ресурсы мы можем вызвать эту функцию напрямую, передав в нее результаты вычислений функции ВычислитьВыражение:
Выбор
Когда Показатель = "п3" Тогда
ОтчетыСервер.РассчитатьПоказательЭффективности(
ВычислитьВыражение("Сумма(Значение)", "Подразделение", , "Первая", "Последняя", "Показатель = ""п1"""),
ВычислитьВыражение("Сумма(Значение)", "Подразделение", , "Первая", "Последняя", "Показатель = ""п2""")
)
Иначе Сумма(Значение)
Конец
Этот подход значительно упрощает отладку кода и позволяет использовать все возможности встроенного языка 1С для вычисления сложных бизнес-показателей в отчетах.