Почему в СКД выводятся единицы и нули вместо сумм из запроса и как это исправить?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Торговля и дистрибуция
← На главную

При разработке отчетов на Схеме компоновки данных (СКД) разработчики часто сталкиваются с непонятным поведением платформы. Один и тот же запрос, запущенный в обычной консоли запросов, возвращает корректные суммированные показатели. Однако стоит перенести его в СКД и сформировать отчет, как вместо ожидаемых итогов выводятся единицы, нули или странные небольшие числа. Создается впечатление, что система выводит количество строк или детальные признаки вместо реальных математических сумм.

В этой статье мы подробно разберем, почему возникает этот эффект, заглянем «под капот» оптимизатора СКД и рассмотрим три практических способа решения этой проблемы.

В чем кроется причина проблемы? Разбор механизмов СКД

Для того чтобы понять, где именно «порылась собака», проанализируем, как СКД обрабатывает исходный текст запроса. Когда в наборе данных включено свойство Автозаполнение, СКД не выполняет запрос в его первозданном виде. Платформа анализирует структуру компоновщика, выбранные поля и группировки в настройках отчета, после чего динамически перестраивает SQL-запрос перед отправкой в СУБД. Это делается для оптимизации: система отсекает неиспользуемые временные таблицы, соединения и поля.

Если в вашем отчете возникают единицы и нули вместо сумм, вы столкнулись с одной из двух архитектурных особенностей СКД:

  1. Отсутствие полей в списке «Ресурсы». Если числовое поле (например, полученное через конструкцию ВЫБОР КОГДА... ТОГДА 1 ИНАЧЕ 0) не добавлено на вкладку «Ресурсы» схемы компоновки, СКД считает его обычным нересурсным полем (измерением или реквизитом). Если в настройках отчета выводится группировка (например, по менеджеру), СКД автоматически добавляет все выбранные нересурсные числовые поля в секцию СГРУППИРОВАТЬ ПО (GROUP BY) результирующего SQL-запроса. СУБД группирует данные по уникальным комбинациям менеджера и признаков (1 и 0), возвращая детальные строки с единицами и нулями вместо итоговой суммы.
  2. Обход финальной группировки оптимизатором. В сложных пакетных запросах со множеством объединений (ОБЪЕДИНИТЬ ВСЕ) и промежуточных таблиц СКД видит, что вы пытаетесь группировать данные и в самом запросе, и в настройках вывода отчета. Пытаясь оптимизировать вычисления, компоновщик может проигнорировать вашу финальную группировку в запросе, обратиться напрямую к детальным записям объединяемых таблиц и сгруппировать их по своим внутренним алгоритмам. Без явно указанных ресурсов это гарантированно приводит к потере агрегирования.

Проанализируем детально структуру запроса, с которым возникли сложности у автора темы:


ВЫБРАТЬ
    втОбщая.РабочийЛистМенеджер,
    СУММА(втОбщая.ТелефонныйЗвонок_1) КАК ТелефонныйЗвонок_1,
    СУММА(втОбщая.КонтактыПоТелефону_2) КАК КонтактыПоТелефону_2,
    ...
ИЗ
    втОбщая КАК втОбщая
СГРУППИРОВАТЬ ПО
    втОбщая.РабочийЛистМенеджер

В консоли запросов группировка по менеджеру отрабатывает идеально. Но в СКД, если поля ТелефонныйЗвонок_1 и КонтактыПоТелефону_2 не объявлены ресурсами, оптимизатор превращает этот блок в детальную выборку без суммирования, группируя строки по значениям этих самых единиц и нулей.

---

Решение №1: Корректное объявление ресурсов в СКД (Рекомендуемый способ)

Самый простой, быстрый и методологически правильный способ исправить поведение отчета — явно указать СКД, что числовые колонки являются ресурсами, которые необходимо суммировать при любых группировках.

Выполним следующие шаги по настройке схемы:

  1. Откроем Схему компоновки данных в конфигураторе 1С или в конструкторе отчетов.
  2. Перейдем на вкладку Ресурсы.
  3. В левом списке доступных полей выделим все наши числовые показатели (в нашем примере это ТелефонныйЗвонок_1, КонтактыПоТелефону_2, ВизитыПослеЗвонка_3 и так далее) и перенесем их в правое окно с помощью кнопки со стрелкой (или двойным кликом).
  4. Убедимся, что в колонке Выражение для каждого добавленного поля автоматически прописалась функция агрегации СУММА(ИмяПоля). При необходимости выражение можно отредактировать вручную.
  5. В колонке Рассчитывать по... оставим значение пустым (чтобы ресурс рассчитывался по всем доступным группировкам и общим итогам).
  6. Переформируем отчет в режиме «1С:Предприятие».

После этой несложной настройки СКД поймет, что данные поля нельзя использовать в качестве ключей группировки SQL-запроса, уберет их из секции СГРУППИРОВАТЬ ПО и применит к ним функцию суммирования на уровне СУБД. Отчет мгновенно примет правильный вид.

---

Решение №2: Перенос агрегации на уровень СКД (Упрощение запроса)

Проектирование тяжелых группировок и итогов внутри самого текста запроса для СКД считается плохой практикой (anti-pattern). Это лишает систему гибкости и перегружает СУБД двойной работой. Проанализируем, как можно оптимизировать исходный пакет запросов.

Рекомендуется упростить финальный запрос пакета, убрав из него искусственную группировку, и передать «плоскую» таблицу детальных записей на обработку компоновщику:

  1. Изменим последний запрос пакета, удалив функции СУММА() и секцию СГРУППИРОВАТЬ ПО. Запрос должен просто выбирать поля из временной таблицы:

ВЫБРАТЬ
    втОбщая.РабочийЛистМенеджер КАК РабочийЛистМенеджер,
    втОбщая.ТелефонныйЗвонок_1 КАК ТелефонныйЗвонок_1,
    втОбщая.КонтактыПоТелефону_2 КАК КонтактыПоТелефону_2,
    втОбщая.ВизитыПослеЗвонка_3 КАК ВизитыПослеЗвонка_3
ИЗ
    втОбщая КАК втОбщая
  1. На вкладке Ресурсы добавим поля ТелефонныйЗвонок_1, КонтактыПоТелефону_2 и настроим для них выражение СУММА(ТелефонныйЗвонок_1).
  2. В настройках структуры отчета (вкладка Настройки) добавим группировку по полю РабочийЛистМенеджер.
  3. В выбранные поля этой группировки добавим наши ресурсы.

При таком подходе СКД сама сформирует максимально эффективный SQL-запрос к СУБД, выберет только нужные записи и мгновенно сгруппирует их в оперативной памяти сервера приложений. Это не только решит проблему с единицами, но и существенно ускорит работу отчета на больших базах данных.

---

Решение №3: Отключение автозаполнения в наборе данных

Если по какой-то причине вам критически важно выполнить SQL-запрос в исходном виде, «один в один», без малейшего вмешательства со стороны механизмов СКД (например, в запросе используются сложные специфические конструкции СУБД или тонко настроенные индексы), можно отключить автоматическое преобразование запроса.

Разберем, как отключить оптимизатор СКД:

  1. Перейдем на вкладку Наборы данных схемы компоновки.
  2. Выберем наш набор данных (запрос).
  3. Найдем флаг Автозаполнение (расположен справа от текста запроса) и снимем с него галочку.
  4. Обратите внимание: после отключения автозаполнения СКД перестанет автоматически определять доступные поля, параметры и роли. Вам потребуется вручную настроить список полей на вкладке «Наборы данных», заполнить их типы и роли, а также настроить параметры на вкладке «Параметры».

Данный метод используется редко и требует от разработчика высокой квалификации, однако он гарантирует, что СУБД выполнит именно тот текст запроса, который вы написали в редакторе.

---

Как провести диагностику и увидеть реальный SQL-запрос?

Чтобы окончательно развеять сомнения и убедиться в том, как именно СКД преобразует ваш код, мы можем программно перехватить макет компоновки и посмотреть итоговый текст запроса. Сделать это можно с помощью внешней обработки «Консоль компоновки данных» или написав несколько строк кода в модуле отчета:


КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);

// В переменной МакетКомпоновки содержится реальный запрос, отправляемый в СУБД
Для Каждого НаборДанных Из МакетКомпоновки.НаборыДанных Цикл
    Если ТипЗнч(НаборДанных) = Тип("НаборДанныхЗапросМакетаКомпоновкиДанных") Тогда
        ЗаписьЖурналаРегистрации("РеальныйЗапросСКД", УровеньЖурналаРегистрации.Информация, , , НаборДанных.Запрос);
    КонецЕсли;
    
КонецЦикла;

Запустив этот код в отладчике, мы наглядно увидим, как СКД превращает нашу финальную группировку в обычную детальную выборку с перечислением единиц и нулей в секции GROUP BY, если поля не были определены как ресурсы. Это знание убережет нас от подобных ошибок при проектировании сложных отчетов в будущем.

← На главную