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

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

При разработке комплексных аналитических отчетов в схеме компоновки данных (СКД) нередко требуется вывести в одной строке показатели продаж за разные временные интервалы: например, продажи за выбранный пользователем основной период, а рядом — оперативные показатели за фиксированные последние 30 и 45 дней. Однако при попытке соединить несколько виртуальных таблиц оборотов с вычислением дат через ДОБАВИТЬКДАТЕ разработчики сталкиваются с тем, что СКД упорно возвращает во всех колонках одинаковые значения — данные за общий период отчета.

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

Причина поведения платформы: механизм автозаполнения СКД

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

Если внутри параметров виртуальной таблицы написать выражение вида:


РегистрНакопления.Продажи.Обороты(ДОБАВИТЬКДАТЕ(&ТекДата, ДЕНЬ, -30), &ТекДата, , ...)

СКД на этапе компоновки макета заменяет эти выражения общими границами периода отчета. В результате все подзапросы получают одинаковые даты среза, и в колонках Прод30 и Прод45 выводятся суммарные продажи за общий период отчета, а не за требуемые 30 и 45 дней.

Рассмотрим рабочие варианты решения этой проблемы.

Способ 1. Использование расширения языка СКД в фигурных скобках

Чтобы запретить платформе автоматически подменять параметры виртуальной таблицы и принудительно зафиксировать расчет периода, воспользуемся синтаксисом расширения языка компоновки данных в фигурных скобках {...}.

Разберем, как модифицировать обращение к виртуальной таблице оборотов:


ВЫБРАТЬ
    ПродажиОбороты.Номенклатура КАК Номенклатура,
    ПродажиОбороты.Склад КАК Склад,
    СУММА(ПродажиОбороты.КоличествоОборот) КАК Продажи
ИЗ
    РегистрНакопления.Продажи.Обороты(
        {(ДОБАВИТЬКДАТЕ(&КонецПериода, ДЕНЬ, -30)) КАК НачалоПериода},
        {(&КонецПериода) КАК КонецПериода},
        ,
        {(Номенклатура).* КАК Номенклатура, (Подразделение).* КАК Подразделение}
    ) КАК ПродажиОбороты
СГРУППИРОВАТЬ ПО
    ПродажиОбороты.Номенклатура,
    ПродажиОбороты.Склад

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

Способ 2. Вынесение интервалов в отдельные параметры схемы СКД

Более прозрачным и легко поддерживаемым подходом является создание отдельных параметров на вкладке «Параметры» схемы компоновки данных.

Разберем настройку по шагам:

  1. В тексте запроса заменим вычисляемые выражения на явные параметры:
    
    // Для таблицы продаж за 30 дней:
    РегистрНакопления.Продажи.Обороты(&ДатаНачала30, &КонецПериода, , )
    
    // Для таблицы продаж за 45 дней:
    РегистрНакопления.Продажи.Обороты(&ДатаНачала45, &КонецПериода, , )
    
  2. Перейдем на вкладку «Параметры» в схеме компоновки данных.
  3. Для параметра ДатаНачала30 в колонке «Выражение» укажем формулу: ДобавитьКДате(&КонецПериода, "День", -30).
  4. Для параметра ДатаНачала45 укажем формулу: ДобавитьКДате(&КонецПериода, "День", -45).
  5. Для обоих параметров установим флаг «Ограничение доступности». Это скроет их от пользователя в пользовательских настройках, и они будут рассчитываться автоматически на основании выбранной даты окончания отчета.

Способ 3. Оптимальный расчет через вычисляемые поля и ресурсы

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

Посмотрим на пример организации расчета:

  1. В запросе выбираем обороты с детализацией по датам:
    
    ВЫБРАТЬ
        ПродажиОбороты.Номенклатура КАК Номенклатура,
        ПродажиОбороты.Склад КАК Склад,
        ПродажиОбороты.ПериодДень КАК ПериодДень,
        ПродажиОбороты.КоличествоОборот КАК КоличествоОборот
    ИЗ
        РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, Авто, ) КАК ПродажиОбороты
    
  2. На вкладке «Вычисляемые поля» создадим поле ПродажиЗа30Дней с выражением:
    
    Выбор
        Когда ПериодДень >= ДобавитьКДате(&КонецПериода, "День", -30)
            Тогда КоличествоОборот
        Иначе 0
    Конец
    
  3. Аналогично создадим поле ПродажиЗа45Дней:
    
    Выбор
        Когда ПериодДень >= ДобавитьКДате(&КонецПериода, "День", -45)
            Тогда КоличествоОборот
        Иначе 0
    Конец
    
  4. На вкладке «Ресурсы» добавим суммирование полей:
    
    Сумма(ПродажиЗа30Дней)
    Сумма(ПродажиЗа45Дней)
    

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

← На главную