SQL-Abfrage Helfen, die für die Queue-Mengen
-
06-07-2019 - |
Frage
Ich habe eine Datenbank, die eine Tabelle " Bestellungen und Inventar Tabelle.
Die um-items-Tabelle hat eine 1 Datensatz pro 1 qty layout, so dass, wenn eine person die Bestellung für 7 'ABC' s, and 4 'XYZ' s, ich bekomme 11 Datensätze in der Tabelle.
id, item, qtyNum 01 ABC 1 02 ABC 2 03 ABC 3 04 ABC 4 05 ABC 5 06 ABC 6 07 ABC 7 08 XYZ 1 09 XYZ 2 10 XYZ 3 11 XYZ 4
Die Tabelle Bestand hat, eine Menge/Stück pro Standort-layout, damit kann ich haben 20 der etwas auf Lager, aber es kann (im schlimmsten Fall) in 20 verschiedenen Standorten.Also für unser Beispiel habe ich den folgenden Bestand:
Qty, Item, Loc, Date 3 'ABC' in Location L1 with date 1990 2 'ABC' in Location L2 with date 1992 5 'ABC' in Location L3 with date 2003 4 'ABC' in Location LH with date 2004 1 'XYZ' in Location L4 with date 1990 2 'XYZ' in Location L5 with date 1993 9 'XYZ' in Location L6 with date 2001 2 'XYZ' in Location LJ with date 2004
*Die H-und J haben keine Besondere Bedeutung!Nur fahren den Punkt nach Hause, dass Sie die neueste
Das Ergebnis einstellen sollte, ziehen Sie so viele wie möglich von den ältesten Standorten ersten, also, für dieses Beispiel, das ich am Ende mit den folgenden "pick queue':
Pick 3 'ABC' from L1 Pick 2 'ABC' from L2 Pick 2 'ABC' from L3 Pick 1 'XYZ' from L4 Pick 2 'XYZ' from L5 Pick 1 'XYZ' from L6
Ich habe eine Lösung, die beinhaltet eine Menge von Ansichten, die sind verbunden mehrere mal mit outer-joins und verrückte Sachen wie das und ich bin nur neugierig, ob es eine einfache/elegante Lösung für dieses problem?Ich konnte es im code kein problem, aber in SQL ich bin kein guru.
MSSQL 2008
Lösung
Puh, das war hart für mich;Ich bin sicher, es gibt elegantere Lösungen als dieses, aber das ist, was ich kam mit:
--test data
DECLARE @orders TABLE
(
ID INT IDENTITY(1, 1) ,
item CHAR(3) ,
Qty INT
)
INSERT INTO @orders
( item, Qty )
VALUES ( 'abc', 1 ),
( 'abc', 2 ),
( 'abc', 3 ),
( 'abc', 4 ),
( 'abc', 5 ),
( 'abc', 6 ),
( 'abc', 7 ),
( 'xyz', 1 ),
( 'xyz', 2 ),
( 'xyz', 3 ),
( 'xyz', 4 )
DECLARE @ItemLoc TABLE
(
Qty INT ,
ITEM CHAR(3) ,
Loc CHAR(2) ,
Dt INT
)
INSERT INTO @ItemLoc
( Qty, ITEM, Loc, Dt )
VALUES ( 3, 'abc', 'L1', 1990 ),
( 2, 'abc', 'L2', 1992 ),
( 5, 'abc', 'L3', 2003 ),
( 4, 'abc', 'LH', 2004 ),
( 1, 'xyz', 'L4', 1990 ),
( 2, 'xyz', 'L5', 1993 ),
( 9, 'xyz', 'L6', 2001 ),
( 2, 'xyz', 'LJ', 2004 ) ;
/*looks complicated, and it is
I use a cte to try to ease it up a bit,
but I first identify a running sum of items
in the bins, and a pull order based on item
and year.
*/
WITH cte
AS ( SELECT a.Qty ,
a.Item ,
a.Loc ,
a.Dt ,
a.RunningSum ,
a.PullOrder ,
b.Qty AS OrderQty
FROM ( SELECT Qty ,
Item ,
Loc ,
Dt ,
RunningSum = ( SELECT SUM(Qty)
FROM @ItemLoc il1
WHERE il1.Item = il.Item
AND il1.Dt <= il.Dt
) ,
PullOrder = ROW_NUMBER() OVER ( PARTITION BY Item ORDER BY Dt )
FROM @ItemLoc il
) a
JOIN ( SELECT item ,
MAX(qty) AS qty
FROM @orders o
GROUP BY item
) b ON a.Item = b.item
)
/* I then use the cte to a) identify the minimum bin
which has a RunningSum of items greater than the OrderQty,
and b) pick all of the items in the bins below that, and
c) pick the remaining items from the last bin
*/
SELECT Pick = CASE WHEN RunningSum <= OrderQty THEN Qty
ELSE OrderQty - ( SELECT SUM(Qty)
FROM cte c3
WHERE c3.item = c1.ITem
AND c3.RunningSum < c1.RunningSum
)
END ,
c1.Item ,
Loc
FROM cte c1
JOIN ( SELECT Item ,
MIN(PullOrder) AS po
FROM cte c2
WHERE RunningSum >= OrderQty
GROUP BY Item
) x ON c1.Item = x.Item
AND c1.PullOrder <= x.po
Andere Tipps
Nach der erneuten Besuch dieses problem, habe ich beschlossen, dass es wäre viel effizienter erstellen Sie eine Tabellenwertfunktion und
Die Abfrage, wie es jetzt steht, ging von 1:45 bis 0:03.Genial.
Leider ich kann nicht nach code, sondern die Allgemeine pseudo-code für die Lösung ist:
Create table-variable zu enthalten alle verfügbaren Plätzen werden können, in irgendeiner Weise gebunden zu einer offenen Bestellung.
Erstellen Sie eine zweite Tabelle variable zu enthalten, die offenen Aufträge.Umfassen Spalten, was Sie brauchen für Status der einzelnen Elemente auf jede Bestellung.
Erstellen Sie die Ergebnistabelle (oder tun Sie dies zuerst, wenn Sie eine Tabellenwertfunktion), die enthält die notwendigen Informationen, die für Ihren pick-Prozess.(Also order#, Artikel #, und was Ort# Sie wollen, es zu ziehen aus.)
Iteration:
von der Anzahl der Datensätze in offenen Aufträge zu 1 von der offenen Aufträgen-Tabelle, Verbindung, wo die Lage hat qty > 0.Speichern Sie jeden pass in die Ergebnis-Tabelle.
Reduzieren Sie die Menge der Position, die Sie gerade eingefügt in die Tabelle mit den Ergebnissen von 1, wenn Sie hatte eine Position aus.(manchmal wird eine Bestellung kann nicht aufsammelbare wegen der Menge oder orderstatus Probleme, aber Sie wollen Sie trotzdem in die Ergebnisse für die Berichterstattung oder Zuteilung Zwecke.) :Ende Der Iteration
Ich Schätze die Hilfe, Stuart Ainsworth, ich wollte nur vermeiden, sub-Abfragen und Zeug.Ich schaffte es, dies zu schreiben, ohne irgendetwas zu schließt sich an den gleichen Tischen mehr als einmal und keinen sub-queries.Stieß Ihr denn seine freakin awesome!