Как в СКД посчитать количество переходов остатка к нулевому значению по дням

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

В процессе разработки аналитической отчетности в 1С часто возникает задача не просто вывести остатки на каждый день, но и проанализировать динамику их изменения. Одной из специфических задач является подсчет количества «обнулений» склада — моментов, когда положительный остаток товара превращается в ноль. Сложность заключается в том, что если товар отсутствует несколько дней подряд, система не должна считать каждый такой день как новый переход; нам нужен только сам факт «падения» в ноль.

В этой статье мы подробно разберем, как реализовать такой расчет в Системе компоновки данных (СКД), рассмотрим использование вычисляемых выражений, работу с запросами и современные возможности платформы 8.3.

Метод 1: Использование функции СКД «ВычислитьВыражение»

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

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

Рассмотрим синтаксис выражения для ресурса:


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

Разберем параметры функции ВычислитьВыражение, которые мы использовали:

  1. "Остаток" — имя поля, значение которого мы хотим получить.
  2. Второй и третий параметры оставлены пустыми, так как мы работаем в контексте текущей группировки.
  3. "Предыдущая" (четвертый и пятый параметры) — указывают системе, что нужно взять значение именно из предыдущей записи относительно текущей.

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

Метод 2: Оконные функции в запросах (для платформы 8.3.20 и выше)

Если вы работаете на современной версии платформы 1С, наиболее производительным решением будет перенос логики в сам запрос. Оконные функции позволяют избежать тяжелых соединений таблиц и выполняются значительно быстрее на больших объемах данных.

Мы можем использовать функцию LAG (в терминах 1С — ПРЕДЫДУЩЕЕ), чтобы получить значение из предыдущей строки прямо в теле запроса. Посмотрим, как это выглядит в конструкторе запроса:


ВЫБРАТЬ
    ПродажиОстатки.Товар,
    ПродажиОстатки.Период,
    ПродажиОстатки.Остаток,
    ВЫБОР
        КОГДА ПродажиОстатки.Остаток = 0 
        И ПРЕДЫДУЩЕЕ(ПродажиОстатки.Остаток) > 0 ТОГДА 1
        ИНАЧЕ 0
    КОНЕЦ КАК ФлагПереходаВНоль
ИЗ
    ВТ_ОстаткиПоДням КАК ПродажиОстатки

В данном случае поле ФлагПереходаВНоль станет обычным числовым полем, которое в СКД достаточно просто просуммировать в ресурсах. Это избавляет систему от необходимости вычислять сложные выражения на этапе компоновки результата.

Метод 3: Самосоединение таблицы (классический подход)

Если использование оконных функций невозможно, проанализируем классический метод с соединением таблицы самой с собой. Суть заключается в том, чтобы к каждой строке с остатком за «сегодня» присоединить строку с остатком за «вчера».

Рассмотрим алгоритм реализации:

  1. Подготовим временную таблицу ВТ_Данные, где собраны остатки по товарам и дням.
  2. Выполним левое соединение этой таблицы с ней же самой по условию: Т1.Товар = Т2.Товар и Т1.Период = ДОБАВИТЬКДАТЕ(Т2.Период, ДЕНЬ, 1).
  3. В условии ГДЕ или в выражении ВЫБОР проверим разницу значений.

Пример кода запроса:


ВЫБРАТЬ
    Сегодня.Товар,
    Сегодня.Период,
    СУММА(ВЫБОР
        КОГДА Сегодня.Остаток = 0 И (Вчера.Остаток > 0 ИЛИ Вчера.Остаток ЕСТЬ NULL)
        ТОГДА 1
        ИНАЧЕ 0
    КОНЕЦ) КАК КоличествоПереходов
ИЗ
    ВТ_Остатки КАК Сегодня
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Остатки КАК Вчера
    ПО Сегодня.Товар = Вчера.Товар
    И Сегодня.Период = ДОБАВИТЬКДАТЕ(Вчера.Период, ДЕНЬ, 1)
СГРУППИРОВАТЬ ПО
    Сегодня.Товар,
    Сегодня.Период

Совет по оптимизации: Самосоединение — довольно ресурсоемкая операция. Чтобы запрос не «зависал» на больших периодах, обязательно проиндексируйте временную таблицу ВТ_Остатки по полям Товар и Период.

Метод 4: Анализ интервалов («Метод островов»)

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

Рассмотрим логику:

  1. Пронумеруем все дни в периоде по порядку (поле НомерДня).
  2. Пронумеруем только те дни, где остаток равен 0 (поле НомерНулевогоДня).
  3. Вычислим разность: Разность = НомерДня - НомерНулевогоДня.

Удивительно, но для каждой непрерывной группы дней с нулевым остатком эта разность будет постоянной величиной. Следовательно, количество различных значений этой Разности и будет равно количеству «переходов» в ноль (или количеству периодов отсутствия товара).

В СКД это реализуется через ресурс: Количество(Различные ВычислитьВыражениеРазность).

Типичные ошибки при реализации

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

Для решения этой проблемы выясним причину отсутствия данных и применим один из следующих приемов:

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

← На главную