2016-09-24 3 views
1

Ich stelle mir vor das ist möglich, aber umfangreiche Forschung und unzählige Stunden haben sich nicht ausgezahlt.Oracle SQL Reset läuft Summe bei Null

Ich verkaufe Produkt aus einem Lagerhaus. Ich weiß, wann ich Sendungen erhalten werde und habe eine tägliche Absatzprognose (in Stückzahl). Ich muss das Endbestand berechnen. Es ist im Grunde eine laufende Summe von Inventar - Prognose.

Das Problem ist, wenn ich kein Produkt mehr habe, werde ich am nächsten Tag kein negatives Inventar haben, wie eine laufende Summe vermuten lässt. Inventar wird Null sein, bis ich eine andere Lieferung erhalte. Es kann in der Prognose mehrfach auf Null gehen (weitaus mehr als im Beispiel unten).

Visual of the dataset (desired column in yellow)

SQL Fiddle for cracking the case

Hier ist meine eigentliche Abfrage:

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 

Spalten

Datum: Die Prognose Datum (starti ng heute)
Tage Out: Die Anzahl der Tage zwischen dem heutigen Tag und dem prognostizierten Datum
Inbound Inventar: kommendes Produkt in (für heute, Produkt hier)
Prognose: Meine geplanten Umsatzmenge
Ending Inventory: Inbound Inventory - Forecast + Wenn das Ending Inventory von gestern < = 0 ist, dann 0 sonst gestern Ending Inventory.

+0

umfassen Bitte geben Sie die Abfrage und Daten in der eigentlichen Frage. –

+0

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

+0

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

Antwort

1

Hier ist eine Lösung mit der MODEL-Klausel (in Oracle 10 eingeführt).

enthalten ich nicht die forecast_date Spalt - days_out genug ist.

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) 
        ) 
) 
; 

Ausgang:

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

Das funktioniert! Absolut brilliant. Ich schätze deine Hilfe sehr. –

1

Konnte das korrekt sein? Es ist etwas, das als rekursiver allgemeiner Tabellenausdruck bezeichnet wird.

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

Nicht nur könnte es, es ist tatsächlich! Ich habe es gerade getestet und es ist perfekt. Bitte beachten Sie: In 'row_number()' ist die Klausel "partition by" nicht obligatorisch, Sie können sie einfach nicht einfügen. (Auf der anderen Seite, wenn das OP tatsächlich durch etwas partitionieren muss, wird es einfacher, diese Änderung zu machen, wenn Sie es so schreiben wie Sie.) Gute Arbeit! – mathguy

+0

@mathguy Danke. Ja ich weiß. Ich mag es einfach, über Dinge klar zu sein. Ihr Kommentar könnte jedoch für das OP nützlich sein. Übrigens, deine MODEL-Lösung scheint auch ganz einfach zu sein. Ich verstehe immer noch nicht das gesamte MODEL-Klausel-Konzept, also kann ich es nicht wirklich sagen. – Demo

+0

Ich habe gerade gelernt, wie man die MODEL-Klausel gestern benutzt (an einem Problem bei OTN) - wenn Sie Zeit und Interesse haben, ist es nicht so kompliziert. Ich bin nicht einmal ein IT-Experte (oder Student), also kann es nicht zu schwierig sein. :-) – mathguy