При разработке отчетов на схеме компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда необходимо объединить данные из нескольких запросов (наборов данных). Типичный пример: в одном запросе мы получаем данные по продажам и прибыли, во втором — расходы на продажу, в третьем — управленческие расходы. Нам нужно посчитать итоговую чистую прибыль по формуле: Прибыль = ПрибыльУбытокОбычная - РасхНаПродажу - УправРасходы.
Однако при выводе отчета итоговая колонка неожиданно оказывается пустой, либо из нее пропадают данные, как только по какой-то из аналитик отсутствует оборот (например, в текущем месяце не было управленческих расходов). Давайте подробно разберем, почему возникает эта проблема, как работает механизм связи наборов данных и как правильно составить выражение ресурса в СКД, чтобы расчеты всегда сходились.
В языке запросов 1С и стандарте SQL любое арифметическое действие со значением NULL возвращает NULL. Если сложить сто тысяч и неопределенность, результатом будет неопределенность:
100 000 - 20 000 - NULL = NULL
Когда вы пытаетесь рассчитать ресурс по формуле:
Сумма(ПрибыльУбытокОбычная) - Сумма(СуммаОборотРасхНаПродажу) - Сумма(СуммаОборотУправРасходы)
И при этом хотя бы по одному из слагаемых (например, по управленческим расходам) за выбранный период не было движений, агрегатная функция Сумма() возвращает NULL. Вся цепочка вычислений рушится, и итоговое поле отображает пустоту.
Многие разработчики пытаются решить эту проблему «в лоб» — прописывая конструкцию ЕСТЬNULL(УправРасходы.СуммаОборот, 0) непосредственно в тексте запроса подчиненного набора данных. Но это не помогает. Почему так происходит?
Дело в том, что когда мы связываем наборы данных на вкладке «Связи наборов данных», СКД объединяет их в собственном процессоре компоновки. Это объединение по своей логике аналогично ЛЕВОМУ СОЕДИНЕНИЮ. Даже если ваш подчиненный запрос вернул ноль, для тех строк главного запроса, по которым нет соответствия в подчиненном, СКД принудительно подставит NULL во все поля подчиненного набора. В итоге обработка NULL внутри текста запроса полностью нивелируется.
---
Для решения проблемы нам нужно обрабатывать неопределенные значения на уровне расчета итогов (ресурсов) СКД. Давайте проанализируем разницу между двумя вариантами написания функции в ресурсах:
Вариант А (Неправильный):
Сумма(ЕСТЬNULL(СуммаОборотУправРасходы, 0))
В данном случае функция ЕСТЬNULL заменяет пустоту на ноль для каждой детальной записи, а затем СКД пытается их просуммировать. Однако если для текущей группировки в подчиненном наборе данных вообще нет ни одной строки (пустая выборка), сам агрегат Сумма() всё равно вернет NULL, и итоговый расчет снова сломается.
Вариант Б (Правильный и надежный):
ЕСТЬNULL(Сумма(СуммаОборотУправРасходы), 0)
Здесь мы сначала рассчитываем агрегат (сумму). Если записей не было и агрегат вернул NULL, вся конструкция целиком заменяется на 0. Это гарантирует стабильный результат математических операций.
Применим этот подход к нашей задаче. На вкладке «Ресурсы» для итогового поля пропишем выражение:
ЕСТЬNULL(Сумма(ПрибыльУбытокОбычная), 0)
- ЕСТЬNULL(Сумма(СуммаОборотРасхНаПродажу), 0)
- ЕСТЬNULL(Сумма(СуммаОборотУправРасходы), 0)
Такой синтаксис гарантирует, что даже при полном отсутствии данных по одной из колонок, расчет будет произведен корректно.
---
Если выражение ресурса получается слишком громоздким (например, когда суммируется более 5-10 показателей), формулу можно упростить с помощью вычисляемых полей:
УправРасходыЧистые.ЕстьNull(СуммаОборотУправРасходы, 0). СКД обработает это выражение на этапе компоновки до расчета итогов.Сумма(УправРасходыЧистые).---
Связи наборов данных в СКД — это ресурсоемкий инструмент. При сложных группировках они могут приводить к «раздваиванию» или потере сумм. Фирма «1С» рекомендует по возможности объединять данные на уровне СУБД в одном запросе.
Вместо связывания трех разных запросов в СКД, спроектируем один запрос, объединяющий таблицы через ОБЪЕДИНЕНИЕ ВСЕХ во временных таблицах:
ВЫБРАТЬ
Продажи.Организация КАК Организация,
Продажи.СуммаОборот КАК Прибыль,
0 КАК РасходыПродажи,
0 КАК РасходыУправленческие
ПОМЕСТИТЬ ВТ_Данные
ИЗ
РегистрНакопления.Продажи.Обороты КАК Продажи
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Расходы.Организация,
0,
Расходы.СуммаОборот,
0
ИЗ
РегистрНакопления.РасходыНаПродажи.Обороты КАК Расходы
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Управ.Организация,
0,
0,
Управ.СуммаОборот
ИЗ
РегистрНакопления.УправленческиеРасходы.Обороты КАК Управ
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_Данные.Организация КАК Организация,
СУММА(ВТ_Данные.Прибыль) КАК Прибыль,
СУММА(ВТ_Данные.РасходыПродажи) КАК РасходыПродажи,
СУММА(ВТ_Данные.РасходыУправленческие) КАК РасходыУправленческие
ИЗ
ВТ_Данные КАК ВТ_Данные
СГРУППИРОВАТЬ ПО
ВТ_Данные.Организация
При таком подходе СКД получит плоскую таблицу без значений NULL (вместо них будут реальные нули), и стандартный расчет ресурсов отработает идеально без дополнительных проверок.
---
Часто разработчики сталкиваются с феноменом: «Я написал формулу с ЕСТЬNULL в ресурсах, но отчет всё равно выводит пустоту!».
Платформа 1С активно кэширует схемы компоновки данных и структуру отчетов в рамках текущего сеанса пользователя. Если вы внесли изменения в ресурсы СКД и просто нажали кнопку «Сформировать», платформа может запустить отчет по старому алгоритму из кэша. Чтобы изменения вступили в силу, выполните следующие действия:
Именно сброс кэша (перезапуск платформы) часто является финальным шагом, после которого верные формулы ресурсов начинают рассчитываться корректно.