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