При разработке сложных отчетов на базе Системы компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда стандартные агрегатные функции начинают вести себя непредсказуемо. Типичный симптом: начальные и конечные остатки в отчете отображаются верно, но итоги по приходу или расходу либо обнуляются, либо «схлопываются» (например, вместо суммы 100 + 100 отчет выводит 100). Особенно часто это проявляется, когда данные собираются не из одной виртуальной таблицы, а через ОБЪЕДИНИТЬ ВСЕ из нескольких временных таблиц.
В этой статье мы разберем, почему СКД искажает обороты при наличии полей остатка, и как правильно настроить набор данных, чтобы расчет итогов работал корректно.
Когда мы используем конструктор запроса и стандартные виртуальные таблицы (ОстаткиИОбороты), СКД автоматически назначает роли полям. Однако, если мы собираем таблицу вручную с помощью UNION, система не понимает, что КоличествоПриход — это оборот, а КоличествоНачальныйОстаток — это остаток на начало периода. В результате механизм расчета ресурсов может ошибочно применять логику расчета остатков к обычным суммируемым полям.
Проанализируем шаги по исправлению ролей:
Остаток. При этом крайне важно, чтобы у обоих полей (Начальный и Конечный) было указано одно и то же Имя в настройках роли (например, Количество), но выбраны соответствующие типы: Начальный и Конечный.Если в отчете мы видим, что сумма двух разных документов реализации по 100 рублей в итоге дает 100 рублей, это явный признак того, что СКД посчитала эти записи дублями. Рассмотрим, почему это происходит. Система компоновки при расчете ресурсов группирует данные по измерениям и периодам. Если в наборе данных не определены ключевые поля, позволяющие однозначно отличить одну запись от другой, СКД может «схлопнуть» их при вычислении итогов.
Для решения этой проблемы выполним следующие действия:
Регистратор и, что еще важнее, НомерСтроки (или уникальный идентификатор записи).Регистратор и ПериодСекунда как обязательные поля или укажем их в качестве ключевых.UNION ALL) в результирующую таблицу попадают все необходимые разрезы данных, включая секунду и регистратор.Рассмотрим ситуацию: автор темы указывает, что использует детализацию по регистратору. В СКД существует жесткое правило: для правильного исчисления и вывода остатков и оборотов в разрезе документов (регистраторов) в запросе обязательно должно присутствовать поле периода с точностью до секунды (ПериодСекунда).
Даже если мы не планируем выводить секунду в отчет, она должна быть в наборе данных. Без этого СКД не сможет правильно упорядочить движения внутри одной даты, что приведет к «каше» в итогах. Пример правильной структуры полей в запросе:
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.Склад,
Остатки.ПериодСекунда,
Остатки.Регистратор,
Остатки.КоличествоНачальныйОстаток,
Остатки.КоличествоПриход,
Остатки.КоличествоРасход,
Остатки.КоличествоКонечныйОстаток
ИЗ
ВТ_ОбъединенныеДанные КАК Остатки
Часто к основной таблице остатков левым соединением подключаются дополнительные данные (цены, упаковки, характеристики). Выясним, как это влияет на итоги. Если для какой-то позиции номенклатуры цена не найдена, в поле цены попадет NULL. В консоли запросов СУММА может работать корректно, но СКД при построении сложного дерева итогов может исключать строки с NULL из расчета определенных ресурсов.
Рекомендация: Всегда оборачивайте числовые поля, получаемые через левое соединение, в функцию ЕСТЬNULL.
ВЫБРАТЬ
Данные.КоличествоПриход,
ЕСТЬNULL(Цены.Цена, 0) КАК Цена,
Данные.КоличествоПриход * ЕСТЬNULL(Цены.Цена, 0) КАК СуммаПриход
ИЗ
ВТ_Движения КАК Данные
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Цены КАК Цены ПО Данные.Номенклатура = Цены.Номенклатура
Проанализируем случай, когда использование временных таблиц блокирует возможность СКД автоматически настраивать параметры. Если мы используем ВременныеТаблицы, СКД не может применить расширение языка запросов для виртуальных таблиц (такое как {ГДЕ ...} или автоматический расчет периодичности).
Если проблему не удается решить настройкой ролей, попробуем изменить архитектуру отчета:
Существует несколько ключевых методик, описанных в документации, которые помогут глубже понять проблему:
UNION. В этом случае критически важно вручную проставить все роли и указать ключевые поля.Важный итог: если вы столкнулись с тем, что «сумма не суммируется», первым делом проверьте наличие поля ПериодСекунда и убедитесь, что в роли поля указано правильное Имя для связи начального и конечного остатка, а обороты (приход/расход) не имеют лишних признаков в колонке Роль.