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

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

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

Анализ исходной проблемы

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


ВЫБРАТЬ
    ЛимитноЗаборныеКарты.Номенклатура,
    ЛимитноЗаборныеКарты.Подразделение,
    ЛимитноЗаборныеКарты.Лимит КАК ТС,
    ЛимитноЗаборныеКарты.Отпущено,
    ЛимитноЗаборныеКарты.Период,
    СУММА(ЛимитноЗаборныеКарты.ОтпущеноСумма) КАК ОтпущеноСумма,
    ЛимитноЗаборныеКарты.Номенклатура.ВидНоменклатуры,
    СУММА(ЛимитноЗаборныеКарты.ОтпущеноСверхЛимитаСумма) КАК ОтпущеноСверхЛимитаСумма,
    МАКСИМУМ(ЛимитыОтпускаМатериаловОрганизацийСрезПоследних.ЛимитОтпускаСумма) КАК ЛимитОтпускаСумма
ИЗ
    РегистрНакопления.ЛимитноЗаборныеКарты КАК ЛимитноЗаборныеКарты
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЛимитыОтпускаМатериаловОрганизаций.СрезПоследних(&ДатаОкончания, ) КАК ЛимитыОтпускаМатериаловОрганизацийСрезПоследних
        ПО ЛимитноЗаборныеКарты.Подразделение = ЛимитыОтпускаМатериаловОрганизацийСрезПоследних.Подразделение
ГДЕ
    ЛимитноЗаборныеКарты.Период МЕЖДУ &ДатаНачала И &ДатаОкончания
    И ЛимитноЗаборныеКарты.Номенклатура.ВидНоменклатуры.Наименование ПОДОБНО "10.05 Запасные части"
СГРУППИРОВАТЬ ПО
    ЛимитноЗаборныеКарты.Номенклатура,
    ЛимитноЗаборныеКарты.Подразделение,
    ЛимитноЗаборныеКарты.Период,
    ЛимитноЗаборныеКарты.Отпущено,
    ЛимитноЗаборныеКарты.Лимит,
    ЛимитноЗаборныеКарты.Номенклатура.ВидНоменклатуры

Проанализируем этот запрос и выделим критические ошибки, которые приводят к искажению данных в отчете.

Причины появления дублей и умножения сумм

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

Способ 1. Использование виртуальной таблицы «Обороты»

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

Перепишем запрос с использованием виртуальной таблицы:


ВЫБРАТЬ
    ЛимитноЗаборныеКартыОбороты.Номенклатура КАК Номенклатура,
    ЛимитноЗаборныеКартыОбороты.Подразделение КАК Подразделение,
    ЛимитноЗаборныеКартыОбороты.ОтпущеноСуммаОборот КАК ОтпущеноСумма,
    ЛимитноЗаборныеКартыОбороты.ОтпущеноСверхЛимитаСуммаОборот КАК ОтпущеноСверхЛимитаСумма,
    ЛимитыОтпускаМатериаловОрганизацийСрезПоследних.ЛимитОтпускаСумма КАК ЛимитОтпускаСумма
ИЗ
    РегистрНакопления.ЛимитноЗаборныеКарты.Обороты(&ДатаНачала, &ДатаОкончания, Авто, Номенклатура.ВидНоменклатуры В (&СписокВидовНоменклатуры)) КАК ЛимитноЗаборныеКартыОбороты
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЛимитыОтпускаМатериаловОрганизаций.СрезПоследних(&ДатаОкончания, ) КАК ЛимитыОтпускаМатериаловОрганизацийСрезПоследних
        ПО ЛимитноЗаборныеКартыОбороты.Подразделение = ЛимитыОтпускаМатериаловОрганизацийСрезПоследних.Подразделение

Важные замечания по оптимизации:

  1. Параметры периода &ДатаНачала и &ДатаОкончания передаются напрямую в параметры виртуальной таблицы, а не в блок ГДЕ.
  2. Фильтрация по виду номенклатуры перенесена в условие виртуальной таблицы через передачу массива или ссылки &СписокВидовНоменклатуры, что исключает неявные соединения и сканирование таблиц по условию ПОДОБНО.

Способ 2. Соединение по всем ключевым измерениям

Если в регистре сведений срез строится по нескольким измерениям, необходимо обязательно связывать таблицы по каждому из них либо отбирать срез строго по конкретной организации в параметрах виртуальной таблицы:


ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЛимитыОтпускаМатериаловОрганизаций.СрезПоследних(
    &ДатаОкончания,
    Организация = &Организация
) КАК ЛимитыОтпускаМатериаловОрганизацийСрезПоследних
    ПО ЛимитноЗаборныеКартыОбороты.Подразделение = ЛимитыОтпускаМатериаловОрганизацийСрезПоследних.Подразделение
    И ЛимитноЗаборныеКартыОбороты.Номенклатура = ЛимитыОтпускаМатериаловОрганизацийСрезПоследних.Номенклатура

Способ 3. Разделение на два набора данных в СКД

Наиболее архитектурно правильным решением при объединении данных разных уровней детализации в СКД является отказ от соединения в тексте SQL-запроса в пользу механизма связей наборов данных:

  1. Создаем НаборДанных1 (Запрос), в котором выбираем только обороты регистра накопления с группировкой по полям Подразделение и Номенклатура.
  2. Создаем НаборДанных2 (Запрос), в котором выбираем срез последних из регистра сведений ЛимитыОтпускаМатериаловОрганизаций.
  3. Переходим на вкладку «Связи наборов данных» и настраиваем связь из «НаборДанных1» в «НаборДанных2» по полям Подразделение (и Номенклатура при наличии).

В этом случае компоновщик данных 1С соединяет агрегированные результаты самостоятельно на этапе вывода отчета, что гарантирует отсутствие декартова произведения и исключает задвоение ресурсов.

Способ 4. Настройка агрегатов на вкладке «Ресурсы»

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

Для корректного расчета общих итогов по иерархии в СКД используют специализированные функции языка выражений:


Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(ЛимитОтпускаСумма)", "Подразделение"))

Такое выражение вычисляет максимальный лимит для каждого отдельного подразделения, собирает эти значения в массив и суммирует только уникальные значения по подразделениям, формируя верный общий итог.

← На главную