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