Как в отчете СКД посчитать количество периодов начиная с момента первой выработки

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

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

В этой статье мы разберем, почему стандартное выражение ВычислитьВыражение может выдавать неверный результат, и рассмотрим несколько надежных способов реализации этой логики.

Анализ проблемы: почему нарастающий итог «замирает» на нулях

Рассмотрим ситуацию, описанную автором: в кросс-таблице по строкам идет продукция, по колонкам — периоды. Нужно создать поле, которое будет показывать «возраст» производства: в первом периоде с производством — 1, во втором — 2 и так далее, даже если во втором периоде количество равно 0. Основная причина проблемы кроется в том, как СКД обрабатывает отсутствие записей в базе данных для конкретного пересечения строки и колонки.

Если в периоде 10:00–11:00 не было движений, то в результате запроса записи для этого часа может просто не существовать. В этом случае функция ВычислитьВыражение, обращаясь к группировке "Период", может возвращать NULL или предыдущее значение, так как контекст вычисления для «пустой» ячейки не определен. Нам же необходимо принудительно заставить систему считать каждый период после «точки старта».

Решение 1: Использование вспомогательного ресурса с точкой старта

Один из самых элегантных способов — это сначала определить дату (или номер периода) самой первой выработки для каждой продукции, а затем в каждой колонке сравнивать текущий период с этой датой. Проанализируем этот алгоритм по шагам.

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

Решение 2: Подготовка данных на уровне SQL-запроса

Если логика в СКД становится слишком громоздкой, мы можем перенести часть вычислений в запрос. Это обеспечит более стабильную работу при расшифровках отчета. Проанализируем ситуацию: нам нужно для каждой записи знать, была ли уже когда-то в прошлом выработка по этой номенклатуре.

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


ВЫБРАТЬ
    Номенклатура,
    МИНИМУМ(Период) КАК ДатаСтарта
ПОМЕСТИТЬ ВТ_ПерваяВыработка
ИЗ
    РегистрНакопления.ВыпускПродукции
ГДЕ
    Количество > 0
СГРУППИРОВАТЬ ПО
    Номенклатура
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ОсновнаяТаблица.Номенклатура,
    ОсновнаяТаблица.Период,
    ОсновнаяТаблица.Количество,
    ВЫБОР
        КОГДА ОсновнаяТаблица.Период >= ЕСТЬNULL(ВТ_ПерваяВыработка.ДатаСтарта, ДАТАВРЕМЯ(3999, 12, 31))
            ТОГДА 1
        ИНАЧЕ 0
    КОНЕЦ КАК ФлагПроизводствоНачато
ИЗ
    ОсновнаяТаблица КАК ОсновнаяТаблица
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПерваяВыработка КАК ВТ_ПерваяВыработка
        ПО ОсновнаяТаблица.Номенклатура = ВТ_ПерваяВыработка.Номенклатура

После такой подготовки в СКД нам остается только просуммировать поле ФлагПроизводствоНачато нарастающим итогом по группировке "Период". Выражение ресурса будет выглядеть так:


ВычислитьВыражение("Сумма(ФлагПроизводствоНачато)", "Период", , "Первая", "Текущая")

Решение 3: Использование функции ВычислитьВыражениеСГруппировкойМассив

Выясним причину, по которой обычная сумма может не работать в кросс-таблице. Если в периоде нет данных, СКД не «видит» строку. Чтобы это обойти, можно использовать массив. Рассмотрим подробнее этот метод. Мы собираем состояния всех предыдущих периодов в массив и считаем его размер или сумму его элементов.

В ресурсах для поля Поле1 можно прописать следующую конструкцию:


Сумма(ВычислитьВыражениеСГруппировкойМассив("Выбор Когда ВычислитьВыражение(""Сумма(Количество)"", ""Период"", , ""Первая"", ""Текущая"") > 0 Тогда 1 Иначе 0 Конец", "Период"))

Важный нюанс: СКД часто ругается на вложенные агрегатные функции (сообщение №10 на форуме). Чтобы избежать ошибки «Вложенные агрегатные функции не допускаются», необходимо убедиться, что внешняя функция Сумма применяется к массиву, который уже содержит вычисленные значения по каждой группировке.

Настройка дополнения периодов

Чтобы колонки с нулевыми значениями вообще отображались в отчете и в них производились вычисления, необходимо правильно настроить поле Период в схеме компоновки данных. Выполним следующие действия:

  1. Перейдем на закладку "Наборы данных".
  2. Найдем поле Период и в колонке "Роль" нажмем на кнопку редактирования.
  3. Убедимся, что указан тип периода (например, День, Месяц).
  4. В настройках отчета на уровне группировки (Колонки) выберем поле Период и установим свойство "Тип дополнения" (например, "День").
  5. Зададим границы дополнения, если это необходимо.

Почему это важно: когда включено дополнение периодов, СКД генерирует виртуальные записи для «пустых» дат. В этом случае функция ВычислитьВыражение будет иметь физическую ячейку для выполнения расчета, и ваш счетчик 1, 2, 3, 4 не прервется, даже если производство в эти дни простаивало.

Обработка NULL в выражениях

Проанализируем ситуацию из сообщения №14, где компоновщик заменяет выражение на NULL. Это часто происходит, если поле, по которому идет упорядочивание в функции ВычислитьВыражение, отсутствует в текущем контексте группировки.

Всегда проверяйте четвертый параметр функции — Сортировка. Если вы считаете итоги по периоду, который является датой, СКД должна четко понимать порядок следования:

ВычислитьВыражение("Сумма(Поле1)", "Период", "Очередность", "Первая", "Текущая")

Где "Очередность" — это направление сортировки. Также рекомендуется оборачивать суммируемые поля в ЕстьNull(Сумма(Количество), 0) прямо внутри строки выражения, чтобы математические операции не приводили к неопределенному результату.

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

← На главную