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