При построении аналитических отчетов в системе 1С часто возникает задача вывести полную матрицу данных: отобразить список всех номенклатурных позиций (например, из определенной группы справочника) по всем календарным дням выбранного интервала, даже если в конкретные дни или за весь период по товарам не было никаких движений.
Если строить отчет обычным обращением к виртуальной таблице Обороты регистра накопления, СУБД вернет только те комбинации дат и товаров, по которым фактически зафиксированы обороты. Если же просто соединить справочник номенклатуры с таблицей оборотов, пропадут дни без продаж. Разберем практические способы решения этой задачи в схеме компоновки данных.
Проанализируем классический подход на уровне запроса схемы компоновки данных. Идея заключается в предварительном формировании полного декартова произведения списка товаров и дат календаря за указанный период, к которому затем левым соединением привязываются фактические обороты.
Разберем построение запроса по шагам:
&ДатаНачала до &ДатаОкончания из регистра сведений календаря (например, КалендарныеГрафики или ПроизводственныйКалендарь).ПО (ИСТИНА).РегистрНакопления.Продажи.Обороты одновременно по номенклатуре и по периоду.Посмотрим на пример текста запроса:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_Номенклатура
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
НЕ Номенклатура.ЭтоГруппа
И НЕ Номенклатура.ПометкаУдаления
{ГДЕ
(Номенклатура.Ссылка В ИЕРАРХИИ (&НоменклатураИерархия))}
СГРУППИРОВАТЬ ПО
Номенклатура.Ссылка
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
КалендарныеГрафики.ДатаГрафика КАК ДатаГрафика
ПОМЕСТИТЬ ВТ_Даты
ИЗ
РегистрСведений.КалендарныеГрафики КАК КалендарныеГрафики
ГДЕ
КалендарныеГрафики.ДатаГрафика МЕЖДУ &ДатаНачала И &ДатаОкончания
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_Даты.ДатаГрафика КАК ДатаГрафика,
ВТ_Номенклатура.Ссылка КАК Номенклатура
ПОМЕСТИТЬ ВТ_Сетка
ИЗ
ВТ_Даты КАК ВТ_Даты
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Номенклатура КАК ВТ_Номенклатура
ПО (ИСТИНА)
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_Сетка.ДатаГрафика КАК ПериодДень,
ВТ_Сетка.Номенклатура КАК Номенклатура,
ЕСТЬNULL(ПродажиОбороты.КоличествоОборот, 0) КАК КоличествоОборот,
ЕСТЬNULL(ПродажиОбороты.СуммаОборот, 0) КАК СуммаОборот
ИЗ
ВТ_Сетка КАК ВТ_Сетка
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(
{(&ДатаНачала)},
{(&ДатаОкончания)},
День,
{Номенклатура В ИЕРАРХИИ (&НоменклатураИерархия)}
) КАК ПродажиОбороты
ПО ВТ_Сетка.Номенклатура = ПродажиОбороты.Номенклатура
И ВТ_Сетка.ДатаГрафика = ПродажиОбороты.Период
Обратите внимание: условие отбора по иерархии номенклатуры важно указывать как в секции выборки справочника, так и в параметрах виртуальной таблицы регистра. Это исключает избыточное чтение движений по позициям, которые не входят в целевую группу.
Если список номенклатуры велик или в конфигурации отсутствует готовый регистр календаря, декартово произведение в запросе может негативно сказаться на производительности СУБД. В этом случае эффективнее воспользоваться встроенным генератором периодов схемы компоновки данных.
Рассмотрим, как настроить отчет с помощью механизма дополнения периодов:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Номенклатура,
ПродажиОбороты.Период КАК ПериодДень,
ПродажиОбороты.КоличествоОборот КАК КоличествоОборот,
ПродажиОбороты.СуммаОборот КАК СуммаОборот
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(
{(&ДатаНачала)},
{(&ДатаОкончания)},
День,
{Номенклатура В ИЕРАРХИИ (&НоменклатураИерархия)}
) КАК ПродажиОбороты
ПО Номенклатура.Ссылка = ПродажиОбороты.Номенклатура
ГДЕ
НЕ Номенклатура.ЭтоГруппа
{ГДЕ
(Номенклатура.Ссылка В ИЕРАРХИИ (&НоменклатураИерархия))}
ПериодДень проверяем корректность роли поля периода (тип ДополнительныйПериод или порядковый номер периода).Номенклатура.ПериодДень.ПериодДень находим раздел «Дополнение периода» и задаем параметры:
День.&ДатаНачала.&ДатаОкончания.При таком подходе СКД сама сгенерирует недостающие колонки дат в результирующей таблице для каждого товара, не перегружая запрос громоздкими соединениями.
Когда товар не продавался в определенный день, в результате левого соединения ресурсные поля принимают значение NULL. Чтобы в отчете выводились аккуратные нули, выполним следующие настройки:
ЕстьNull(Сумма(КоличествоОборот), 0) и ЕстьNull(Сумма(СуммаОборот), 0).ЧН=0 (представление нуля).Применение этих методов позволяет получить структурированную матрицу продаж за любой выбранный интервал времени с гарантированным отображением всех товаров и всех дней периода.