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

War es hilfreich?

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!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top