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