При разработке отчетов на базе Системы компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда детальные записи (по документам) показывают верные суммы, но при попытке вывести общие итоги или сгруппировать данные по контрагенту, цифры становятся меньше ожидаемых. Рассмотрим классический пример: в детальном списке мы видим три документа с суммами 10 000, 10 000 и 3 000. Логично ожидать общую сумму 23 000, однако система выдает 13 000. Выясним причину этого поведения и разберем по шагам, как исправить запрос.
Проанализируем фрагмент запроса, который привел к ошибке. Основная причина "исчезновения" данных кроется в финальной части выборки:
ВЫБРАТЬ
ОбъедПоступ.Договор КАК Договор,
ОбъедПоступ.Контрагент КАК Контрагент,
ОбъедПоступ.СчетНаОплату КАК СчетНаОплату,
ЕСТЬNULL(ОбъедПоступ.СуммаПоступлениеНаСчет, 0) + ЕСТЬNULL(ОбъедПоступ.СуммаПоступлениеВКассу, 0) КАК Поступление,
...
ИЗ
ОбъедПоступ КАК ОбъедПоступ
СГРУППИРОВАТЬ ПО
...
ЕСТЬNULL(ОбъедПоступ.СуммаПоступлениеНаСчет, 0) + ЕСТЬNULL(ОбъедПоступ.СуммаПоступлениеВКассу, 0)
В данном коде поле Поступление включено в секцию СГРУППИРОВАТЬ ПО. В терминах баз данных это означает, что система ищет уникальные комбинации всех указанных полей. Если у вас есть два разных документа с одинаковой суммой (например, 10 000), и вы группируете по полю суммы, для СУБД это одна и та же категория значения. В результате две строки по 10 000 "схлопываются" в одну. Вместо сложения (10 000 + 10 000) вы получаете просто уникальное значение 10 000.
Чтобы получить заветные 23 000, необходимо изменить подход к группировке. Поля, которые должны суммироваться, нельзя включать в секцию СГРУППИРОВАТЬ ПО. Вместо этого к ним нужно применить агрегатную функцию СУММА() в блоке ВЫБРАТЬ.
Рассмотрим, как должен выглядеть исправленный фрагмент запроса:
ВЫБРАТЬ
ОбъедПоступ.Договор КАК Договор,
ОбъедПоступ.Контрагент КАК Контрагент,
ОбъедПоступ.СчетНаОплату КАК СчетНаОплату,
СУММА(ЕСТЬNULL(ОбъедПоступ.СуммаПоступлениеНаСчет, 0) + ЕСТЬNULL(ОбъедПоступ.СуммаПоступлениеВКассу, 0)) КАК Поступление,
ОбъедПоступ.СчетНаОплатуСуммаДокумента КАК СчетНаОплатуСуммаДокумента
ИЗ
ОбъедПоступ КАК ОбъедПоступ
СГРУППИРОВАТЬ ПО
ОбъедПоступ.Договор,
ОбъедПоступ.Контрагент,
ОбъедПоступ.СчетНаОплату,
ОбъедПоступ.СчетНаОплатуСуммаДокумента
Теперь система будет брать все записи, соответствующие конкретному счету на оплату, и складывать их суммы, а не просто отсекать дубликаты цифр.
Если вы работаете в Системе компоновки данных, наиболее правильным и гибким способом будет перенос агрегации из текста запроса в настройки самой компоновки. Рассмотрим этот алгоритм подробнее:
СГРУППИРОВАТЬ ПО из финального запроса, если вам нужны детальные записи. Позвольте СКД получить "сырые" данные.Поступление в правую колонку.СУММА(Поступление). Это именно то, что нужно для корректного расчета итогов по иерархии (контрагентам, договорам и т.д.).Преимущество этого метода в том, что СКД сама управляет группировками в зависимости от настроек отчета пользователя. Если пользователь удалит группировку по документам, СКД автоматически пересчитает итог по родителю (например, по контрагенту), используя указанную функцию СУММА().
Проанализируем еще одну потенциальную точку потери данных в вашем запросе. В первом временном пакете используется оператор ОБЪЕДИНИТЬ:
...
ИЗ
Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
ГДЕ
...
ОБЪЕДИНИТЬ
ВЫБРАТЬ
...
Важно помнить, что оператор ОБЪЕДИНИТЬ (без слова ВСЕ) выполняет операцию DISTINCT над всем результирующим набором. Если две разные ветки запроса вернут абсолютно идентичные строки (одинаковый контрагент, одинаковый договор, одинаковые суммы), то в результат попадет только одна из них. Чтобы избежать случайной потери данных, всегда используйте ОБЪЕДИНИТЬ ВСЕ, если вы не преследуете цель намеренного удаления дублей.
В представленном запросе выполняется ЛЕВОЕ СОЕДИНЕНИЕ с табличной частью ДополнительныеРеквизиты. Рассмотрим ситуацию: если у одного договора в табличной части окажется две записи, удовлетворяющие условию ГДЕ, то основная запись договора в результате запроса удвоится. Соответственно, сумма по этому договору также увеличится в два раза при последующем суммировании.
Чтобы избежать подобных "сюрпризов", рекомендуется:
Таким образом, для получения корректных 23 000 вместо 13 000, вам достаточно убрать сумму из секции группировки и обернуть её в функцию СУММА(), а также убедиться, что использование ОБЪЕДИНИТЬ не "съедает" одинаковые строки данных на промежуточных этапах.