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