Почему СКД объединяет строки с одинаковыми суммами и как это исправить

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

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

Разберем детально механизм возникновения этой ошибки и рассмотрим практические способы ее устранения.

Проанализируем типовую ситуацию на примере запроса набора данных, формирующего остатки и движения денежных средств:


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    ДвиженияДенежныхСредствОбороты.ВидДенежныхСредств КАК ВидДенежныхСредств,
    ДвиженияДенежныхСредствОбороты.СтатьяДвиженияДенежныхСредств КАК СтатьяДвиженияДенежныхСредств,
    ДвиженияДенежныхСредствОбороты.ДокументДвижения,
    ВЫБОР
        КОГДА ДвиженияДенежныхСредствОбороты.ПриходРасход.Порядок = 0
            ТОГДА ДвиженияДенежныхСредствОбороты.СуммаОборот
        ИНАЧЕ 0
    КОНЕЦ КАК Приход,
    ВЫБОР
        КОГДА ДвиженияДенежныхСредствОбороты.ПриходРасход.Порядок = 1
            ТОГДА ДвиженияДенежныхСредствОбороты.СуммаОборот
        ИНАЧЕ 0
    КОНЕЦ КАК Расход,
    ДвиженияДенежныхСредствОбороты.Организация КАК Организация,
    ВЫБОР
        КОГДА ДвиженияДенежныхСредствОбороты.Подразделение <> ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка)
            ТОГДА ДвиженияДенежныхСредствОбороты.Подразделение
        ИНАЧЕ ДвиженияДенежныхСредствОбороты.ДокументДвижения.Подразделение
    КОНЕЦ КАК Подразделение
ПОМЕСТИТЬ Обороты
ИЗ
    РегистрНакопления.ДвиженияДенежныхСредств.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ДвиженияДенежныхСредствОбороты
СГРУППИРОВАТЬ ПО
    ДвиженияДенежныхСредствОбороты.ВидДенежныхСредств,
    ДвиженияДенежныхСредствОбороты.СтатьяДвиженияДенежныхСредств,
    ДвиженияДенежныхСредствОбороты.ДокументДвижения,
    ВЫБОР
        КОГДА ДвиженияДенежныхСредствОбороты.ПриходРасход.Порядок = 0
            ТОГДА ДвиженияДенежныхСредствОбороты.СуммаОборот
        ИНАЧЕ 0
    КОНЕЦ,
    ВЫБОР
        КОГДА ДвиженияДенежныхСредствОбороты.ПриходРасход.Порядок = 1
            ТОГДА ДвиженияДенежныхСредствОбороты.СуммаОборот
        ИНАЧЕ 0
    КОНЕЦ,
    ДвиженияДенежныхСредствОбороты.Организация,
    ВЫБОР
        КОГДА ДвиженияДенежныхСредствОбороты.Подразделение <> ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка)
            ТОГДА ДвиженияДенежныхСредствОбороты.Подразделение
        ИНАЧЕ ДвиженияДенежныхСредствОбороты.ДокументДвижения.Подразделение
    КОНЕЦ

Причины некорректного поведения отчета

Выясним причину такого поведения платформы. Ошибка возникает из-за сочетания двух факторов:

  1. Ошибочная группировка по числовым выражениям вместо агрегации: В тексте запроса поля Приход и Расход не рассчитываются через агрегатную функцию СУММА(), а включены напрямую в блок СГРУППИРОВАТЬ ПО. Пока в выборке присутствует уникальный регистратор ДокументДвижения, строки не склеиваются, так как каждая запись уникальна.
  2. Механизм автозаполнения СКД: Если поле ДокументДвижения не выводится в выбранных полях отчета и не участвует в группировках, компоновщик макета СКД в целях оптимизации исключает неиспользуемое поле из секций ВЫБРАТЬ и СГРУППИРОВАТЬ ПО. Лишившись уникального ключа, СУБД группирует строки только по оставшимся измерениям и полям сумм. В результате все 10 записей с суммой 8000 признаются абсолютно одинаковыми и схлопываются в одну строку.

Способ 1. Исправление запроса и настройка ресурсов (Рекомендуемое решение)

Рассмотрим правильный архитектурный подход к устранению проблемы. Необходимо переписать запрос так, чтобы суммовые поля агрегировались стандартными средствами языка запросов, а не группировались:

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

Посмотрим на пример исправленного фрагмента запроса:


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    ДвиженияДенежныхСредствОбороты.ВидДенежныхСредств КАК ВидДенежныхСредств,
    ДвиженияДенежныхСредствОбороты.СтатьяДвиженияДенежныхСредств КАК СтатьяДвиженияДенежныхСредств,
    ДвиженияДенежныхСредствОбороты.ДокументДвижения КАК ДокументДвижения,
    СУММА(ВЫБОР
        КОГДА ДвиженияДенежныхСредствОбороты.ПриходРасход.Порядок = 0
            ТОГДА ДвиженияДенежныхСредствОбороты.СуммаОборот
        ИНАЧЕ 0
    КОНЕЦ) КАК Приход,
    СУММА(ВЫБОР
        КОГДА ДвиженияДенежныхСредствОбороты.ПриходРасход.Порядок = 1
            ТОГДА ДвиженияДенежныхСредствОбороты.СуммаОборот
        ИНАЧЕ 0
    КОНЕЦ) КАК Расход,
    ДвиженияДенежныхСредствОбороты.Организация КАК Организация,
    ВЫБОР
        КОГДА ДвиженияДенежныхСредствОбороты.Подразделение <> ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка)
            ТОГДА ДвиженияДенежныхСредствОбороты.Подразделение
        ИНАЧЕ ДвиженияДенежныхСредствОбороты.ДокументДвижения.Подразделение
    КОНЕЦ КАК Подразделение
ПОМЕСТИТЬ Обороты
ИЗ
    РегистрНакопления.ДвиженияДенежныхСредств.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ДвиженияДенежныхСредствОбороты
СГРУППИРОВАТЬ ПО
    ДвиженияДенежныхСредствОбороты.ВидДенежныхСредств,
    ДвиженияДенежныхСредствОбороты.СтатьяДвиженияДенежныхСредств,
    ДвиженияДенежныхСредствОбороты.ДокументДвижения,
    ДвиженияДенежныхСредствОбороты.Организация,
    ВЫБОР
        КОГДА ДвиженияДенежныхСредствОбороты.Подразделение <> ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка)
            ТОГДА ДвиженияДенежныхСредствОбороты.Подразделение
        ИНАЧЕ ДвиженияДенежныхСредствОбороты.ДокументДвижения.Подразделение
    КОНЕЦ

В этом случае, даже если компоновщик исключит ДокументДвижения из результирующего SQL-запроса, СУБД корректно сложит 10 записей и вернет 80 000 рублей.

Способ 2. Установка признака «Обязательное» в роли поля

Разберем быстрый способ исправления в настройках СКД без глубокой модификации логики запроса:

  1. Откройте схему компоновки данных и перейдите на вкладку Наборы данных.
  2. В таблице доступных полей найдите поле ДокументДвижения.
  3. В колонке Роль откройте окно редактирования роли поля.
  4. Установите флаг Обязательное и подтвердите выбор.

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

Способ 3. Отключение автозаполнения набора данных

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

При использовании данного способа все поля отбора, группировок и порядка потребуется настраивать вручную с использованием специального синтаксиса расширения языка запросов СКД (конструкции вида {ВЫБРАТЬ ...}, {ГДЕ ...}).

← На главную