Почему отчет СКД в 1С меняет итоги при добавлении полей и отличается от внешнего отчета?

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

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

Причина 1: Динамическая оптимизация запросов в СКД

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

  1. Исключение неиспользуемых соединений: Если в исходном тексте запроса СКД присутствует конструкция ЛЕВОЕ СОЕДИНЕНИЕ, но поля из присоединяемой таблицы не выбраны в отчете, не участвуют в группировках, отборах или сортировках, СКД полностью вырезает эту секцию соединения из итогового SQL-запроса для экономии ресурсов СУБД.
  2. Размножение строк при включении поля: Как только мы добавляем в отчет любое поле из ранее не задействованной таблицы, СКД включает вырезанное соединение обратно в запрос. Если связь между таблицами не является строго «один к одному», а содержит дублирующиеся ключи («один ко многим»), происходит умножение записей базовой таблицы. В результате детальные записи размножаются, а ресурсы по числовым полям задваиваются или кратно увеличиваются.
  3. Поведение консоли запросов: Консоль запросов выполняет текст запроса целиком, без динамической оптимизации СКД. Поэтому результат консоли и внешнего отчета (если в нем выбраны все поля) совпадает, но отличается от встроенного отчета с оптимизированным запросом.

Причина 2: Разница контекста встроенного и внешнего отчетов

Проанализируем, почему выгруженный во внешний файл отчет может сразу выдавать другие данные по сравнению со встроенным:

  1. Сохраненные пользовательские настройки: Встроенный отчет при открытии восстанавливает сохраненные пользовательские настройки, варианты и скрытые отборы из системного хранилища (например, ХранилищеВариантовОтчетов). Внешний отчет запускается с чистыми настройками схемы по умолчанию, где эти скрытые фильтры отсутствуют.
  2. Обработка в общих модулях: В типовых конфигурациях при открытии и формировании встроенных отчетов вызываются процедуры стандартизированных подсистем. Проверки внутри общих модулей нередко завязаны на тип или полное имя объекта метаданных. Для внешнего отчета такие алгоритмы не срабатывают, что меняет поведение компоновки.
  3. Ограничения доступа (RLS): Механизмы ограничения прав на уровне записей могут по-разному применять параметры сеанса и контекст выполнения для объектов конфигурации и внешних файлов.

Диагностика: получение фактического текста запроса СКД

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


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

Для Каждого НаборДанных Из МакетКомпоновки.НаборыДанных Цикл
    Если ТипЗнч(НаборДанных) = Тип("НаборДанныхЗапросКомпоновкиДанных") Тогда
        ТекстРеальногоЗапроса = НаборДанных.Запрос;
        Сообщить("Фактический запрос СКД:");
        Сообщить(ТекстРеальногоЗапроса);
    КонецЕсли;
КонецЦикла;

Сравним текст полученного запроса до и после добавления поля: мы увидим появление секций ЛЕВОЕ СОЕДИНЕНИЕ или дополнительных условий в секции ГДЕ.

Способы исправления проблемы

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

Вариант 1. Разделение на независимые наборы данных

Вместо объединения таблиц через ЛЕВОЕ СОЕДИНЕНИЕ внутри одного текста запроса вынесем присоединяемую таблицу в отдельный Набор данных - запрос. Свяжем наборы на вкладке Связи наборов данных схемы компоновки. В этом случае СКД самостоятельно выполнит соединение результатов на уровне процессора компоновки без физического умножения строк базового набора и без искажения ресурсов.

Вариант 2. Группировка присоединяемой таблицы

Если необходимо оставить связь внутри одного запроса, гарантируем уникальность ключей во второй таблице. Для этого предварительно сгруппируем ее во временной таблице по полям связи с использованием агрегатных функций (МАКСИМУМ или МИНИМУМ), исключая появление дублей по ключу соединения.

Вариант 3. Настройка выражений ресурсов

Если размножение строк неизбежно из-за структуры данных, скорректируем расчет итогов на вкладке Ресурсы. Используем поле Рассчитывать по или специальные функции языка выражений СКД, например расчет ресурса по уникальным группировкам через Сумма(ВычислитьВыражениеСГруппировкойМассив(...)), чтобы исключить повторный учет дублированных записей в итогах.

Вариант 4. Сброс пользовательских настроек

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

← На главную