Количество дней, когда товар был на складе

FastCode 63 8

Обычный подход к решению этой задачи - рассчитать "остатки на каждый день" и подсчитать дни наличия товара. Предлагается другой подход: найти все интервалы отсутствия товара и вычесть их общую длину из длины периода. Получается следующий запрос:

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

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
    Движения.Склад,
    Движения.Номенклатура,
    Движения.Период,
    Движения.КоличествоНачальныйОстаток,
    Движения.КоличествоКонечныйОстаток
ПОМЕСТИТЬ ДополненныеДвижения
ИЗ
    Движения КАК Движения

ОБЪЕДИНИТЬ

ВЫБРАТЬ РАЗЛИЧНЫЕ
    НачальныеНули.Склад,
    НачальныеНули.Номенклатура,
    &НачалоПериода,
    0,
    0
ИЗ
    Движения КАК НачальныеНули

ОБЪЕДИНИТЬ

ВЫБРАТЬ РАЗЛИЧНЫЕ
    КонечныеНули.Склад,
    КонечныеНули.Номенклатура,
    &КонецПериода,
    0,
    0
ИЗ
    Движения КАК КонечныеНули
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
    Точки.Склад,
    Точки.Номенклатура,
    Точки.Период,
    МАКСИМУМ(Точки.КоличествоНачальныйОстаток) КАК КоличествоНачальныйОстаток,
    МАКСИМУМ(Точки.КоличествоКонечныйОстаток) КАК КоличествоКонечныйОстаток
ПОМЕСТИТЬ ТочкиВремени
ИЗ
    ДополненныеДвижения КАК Точки

СГРУППИРОВАТЬ ПО
    Точки.Склад,
    Точки.Номенклатура,
    Точки.Период
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
    Точки.Склад,
    Точки.Номенклатура,
    МАКСИМУМ(Слева.Период) КАК НачалоОтсутствия,
    Точки.Период
ПОМЕСТИТЬ Интервалы
ИЗ
    ТочкиВремени КАК Точки
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТочкиВремени КАК Слева
        ПО Точки.Склад = Слева.Склад
            И Точки.Номенклатура = Слева.Номенклатура
            И (Точки.КоличествоНачальныйОстаток = 0)
            И (Слева.КоличествоКонечныйОстаток = 0)
            И Точки.Период > Слева.Период

СГРУППИРОВАТЬ ПО
    Точки.Склад,
    Точки.Номенклатура,
    Точки.Период

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ РАЗЛИЧНЫЕ
    Точки.Склад,
    Точки.Номенклатура,
    &КонецПериода,
    &НачалоПериода
ИЗ
    Движения КАК Точки
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
    Интервалы.Склад,
    Интервалы.Номенклатура,
    СУММА(РАЗНОСТЬДАТ(Интервалы.Период, Интервалы.НачалоОтсутствия, СЕКУНДА)) / 60 / 60 / 24 КАК ДнейНаличия
ИЗ
    Интервалы КАК Интервалы

СГРУППИРОВАТЬ ПО
    Интервалы.Склад,
    Интервалы.Номенклатура

Чтобы обработать "особые случаи" (когда в начале или в конце интервала остаток будет нулевым), потребовалось добавить записи - "заглушки" по краям интервала. Чтобы учесть возможность, когда периодов отсутствия не было, потребовалось добавить записи полного интервала, из которых при группировке вычитаются интервалы отсутствия.
Из-за этих особых случаев запрос получился длинным, но по идее он простой. Большим плюсом этого подхода является то, что он замечает движения в течении дня. Если же ориентироваться только на остатки в начале/конце дня, то на складе типа "гардероб" (завезли и тут же продали) товар будет всегда отсутствовать.

Возможно, при небольшом объеме данных необходимости повышать быстродействие, выделяя более редкие интервалы отсутствия товаров, и не возникнет. Тогда можно просуммировать собственно интервалы наличия, что выливается в гораздо более короткий запрос (сразу для дней, но можно переделать и для секунд):

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

Автор: ildarovich

TurboConf - расширение Конфигуратора 1С

Похожие публикации

Количество дней недели (понедельников/вторников/...) в заданном диапазоне одним запросом

Определение суммарного покрытия перекрывающихся интервалов

Проверка совпадения таблиц путем сравнения полного и внутреннего соединения

Получить дату через указанное количество [дней, месяцев, лет, ...]

Модератору