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