2016-09-24 2 views
1

Я предполагаю, что это возможно, но обширные исследования и бесчисленные часы не окупились.Oracle SQL Reset Running Sum When Zero

Я продаю продукт со склада. Я знаю, когда буду получать отгрузки, и у меня есть ежедневный прогноз продаж (в количестве). Мне нужно рассчитать окончательный инвентарь. Это в основном текущая сумма Inventory - Forecast.

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

Visual of the dataset (desired column in yellow)

SQL Fiddle for cracking the case

Вот мой фактический запрос:

SELECT FORECAST_DATE, DAYS_OUT, INBOUND_INVENTORY, FORECAST, 
     ENDING_INVENTORY AS DESIRED_RESULT, 
     SUM(INBOUND_INVENTORY) OVER (PARTITION BY NULL ORDER BY DAYS_OUT) - 
      SUM(FORECAST) OVER (PARTITION BY NULL ORDER BY DAYS_OUT) AS ENDING_INVENTORY 
FROM MRP 

Колонна

Дата: Дата прогноза (ЗАПУСК нг сегодня)
Days Out: Количество дней между сегодняшним днем ​​и датой прогноза
Inbound Inventory: Продукт подходит в (на сегодняшний день, продукт здесь)
Прогноз: Мой планируемое количество продаж
Конечная инвентаризация: Входящая инвентаризация - прогноз + Если вчерашний законный инвентарь < = 0, то 0 еще вчерашний инвентарь завершения.

+0

Пожалуйста, включите запрос и данные в актуальном вопросе. –

+0

ВЫБОР FORECAST_DATE, DAYS_OUT, INBOUND_INVENTORY, FORECAST, ENDING_INVENTORY, как DESIRED_RESULT, SUM (INBOUND_INVENTORY) НАД (PARTITION BY NULL ORDER BY DAYS_OUT) - SUM (ПРОГНОЗ) НАД (PARTITION BY NULL ORDER BY DAYS_OUT) AS ENDING_INVENTORY ОТ MRP –

+0

http://sqlfiddle.com/#!4/72750/10 –

ответ

1

Это решение с использованием предложения MODEL (представлено в Oracle 10).

Я не включил колонку forecast_date - days_out достаточно.

with 
    inputs (days_out, inbound_inventory, forecast) as (
     select 0, 24, 0 from dual union all 
     select 1, 0, 124 from dual union all 
     select 2, 0, 154 from dual union all 
     select 3, 0, 316 from dual union all 
     select 4, 780, 119 from dual union all 
     select 5, 780, 148 from dual union all 
     select 6, 780, 123 from dual union all 
     select 7, 0, 168 from dual union all 
     select 8, 0, 323 from dual union all 
     select 9, 0, 184 from dual union all 
     select 10, 0, 331 from dual union all 
     select 11, 0, 149 from dual union all 
     select 12, 0, 431 from dual union all 
     select 13, 0, 153 from dual union all 
     select 14, 0, 183 from dual union all 
     select 15, 0, 169 from dual union all 
     select 16, 0, 169 from dual union all 
     select 17, 780, 331 from dual 
    ) 
select days_out, inbound_inventory, forecast, ending_inventory 
from inputs 
model 
    dimension by (days_out) 
    measures  (inbound_inventory, forecast, 0 ending_inventory) 
    rules update 
    iterate(1000000) until (previous(ending_inventory[iteration_number + 1]) is null) 
    (
    ending_inventory[iteration_number] = 
      greatest (0, inbound_inventory[cv()] - forecast[cv()] 
          + nvl(ending_inventory[cv() - 1], 0) 
        ) 
) 
; 

Выход:

DAYS_OUT INBOUND_INVENTORY FORECAST ENDING_INVENTORY 
---------- ----------------- ---------- ---------------- 
     0    24   0    24 
     1     0  124    0 
     2     0  154    0 
     3     0  316    0 
     4    780  119    661 
     5    780  148    1293 
     6    780  123    1950 
     7     0  168    1782 
     8     0  323    1459 
     9     0  184    1275 
     10     0  331    944 
     11     0  149    795 
     12     0  431    364 
     13     0  153    211 
     14     0  183    28 
     15     0  169    0 
     16     0  169    0 
     17    780  331    449 

18 rows selected. 
+0

Это работает! Абсолютно блестящий. Я действительно ценю твою помощь. –

1

Это может быть правильным? Это то, что называется рекурсивным общим табличным выражением.

WITH 
cte_mrp as 
(
    Select row_number() over (partition by null order by forecast_date) as line, mrp.* 
    From mrp 
), 
RCTE (line, forecast_date, days_out, inbound_inventory, forecast, /*iteration, anchor,*/ ending_inventory) as 
(
    Select line, forecast_date, days_out, inbound_inventory, forecast, /*0 iteration, 'anchor' anchor,*/ 
     CASE WHEN inbound_inventory-forecast < 0 THEN 0 ELSE inbound_inventory-forecast END ending_inventory 
    From cte_mrp 
    Where line = 1 

    union all 

    Select m.line, m.forecast_date, m.days_out, m.inbound_inventory, m.forecast, /*r.iteration + 1, 'rcte' anchor,*/ 
     CASE WHEN r.ending_inventory+m.inbound_inventory - m.forecast < 0 THEN 0 ELSE r.ending_inventory+m.inbound_inventory - m.forecast END ending_inventory 
    From cte_mrp m 
    Inner join rcte r on (r.line = (m.line-1)) 
) 

Select * From RCTE; 
+0

Не только это возможно, на самом деле это! Я просто проверял, и это прекрасно. Обратите внимание: в 'row_number()' предложение "partition by" не является обязательным, вы можете просто не помещать его вообще. (С другой стороны, если на самом деле OP нужно что-то переделать, написание его, как и вы, облегчит это изменение.) Хорошая работа! – mathguy

+0

@mathguy Спасибо. Да, знаю. Мне просто нравится говорить о вещах. Ваш комментарий может быть полезен для OP. Кстати, ваше решение MODEL кажется слишком аккуратным, только я все еще не в состоянии понять всю концепцию предложения MODEL, поэтому я не могу сказать. – Demo

+0

Я только что узнал, как использовать предложение MODEL вчера (работа над проблемой в OTN) - если у вас есть время и интерес, это не так сложно. Я даже не специалист по ИТ (или студент), поэтому это не может быть слишком сложно. :-) – mathguy

Смежные вопросы