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