Ilya Sh, ich konnte nicht ganz überprüfen, ob Ihre eigene Antwort auf Ihre Frage richtig war. Aber hier ist mein Ansatz.
Ursprünglich dachte ich, dass dies mit einer rekursiven Abfrage gelöst werden könnte, aber das ist, wo alle Boxen gleich groß und garantiert größer als die Elemente sind, und die Elemente sind unteilbar, aber variieren in der Größe (so dass die einzige Entscheidung in Bezug auf jeden Artikel ist, ob es in der aktuellen Box verpackt werden kann, oder in der nächsten Box gehen muss).
In diesem Fall haben wir Gruppen von Elementen (dh eine Zeile, die einen Elementtyp und eine Menge angibt), in der die Elemente gleich groß sind, die Gruppen jedoch teilbar sind und jede Elementgruppe daher über eine Nummer verteilt werden kann von Boxen, und jede Box kann Teile einer Anzahl von Elementgruppen in einer Viele-zu-Viele-Beziehung zwischen Boxen und Elementgruppen enthalten.
Mein Denken ist, dass jede Box, je nach ihrer Kapazität, eine Reihe von einzelnen "Slots" (d. H. Ein Volumen von Raum), die einzelne Elemente erhalten kann.
Der Weg zu der Lösung besteht darin, eine "Nummerentabelle" zu verwenden, um die Mengen jeder Box/Artikelgruppe in einzelne Box-Slots und einzelne Artikel zu erweitern - eine Zeile pro Box-Slot und eine Zeile pro Artikel . Auf meinem Computer habe ich eine Tabelle namens zx_numbers - aber ich habe Code darunter eingefügt, der die Abhängigkeit von dieser Tabelle zu Illustrationszwecken beseitigt.
Sobald wir die Daten auf diese Weise normalisiert haben - indem wir Boxen in ihre einzelnen Slots expandieren und die Artikelgruppen und Summenmengen in einzelne Artikel expandieren - wird jeder Boxplatz und Artikel im gesamten Stapel fortlaufend nummeriert Zwei werden einfach auf dieser Sequenznummer zusammengefügt.
Ich habe eine FULL OUTER JOIN
verwendet, um unübertroffene Slots/Elemente zu erhalten. Dies gibt uns eine sehr allgemeine und anpassungsfähige Lösung für das Problem, die wir dann auf verschiedene Weise weiterverarbeiten können, um die spezifischen Daten zu erhalten, die wir wollen (in diesem Fall nur eine Zusammenfassung der Kombinationen aus Box und Artikelgruppe).
Die Art und Weise, wie ich die Abfrage geschrieben habe, sind Boxen mit nicht gefülltem Speicherplatz (oder Artikelgruppen, die einen Rest hinterlassen, nachdem alle Felder vollständig ausgefüllt wurden) in den Ergebnissen und am Ende platziert, aber diese können gefiltert werden wenn nicht erforderlich.
WITH
item_groups(item_group_id, group_qty) AS
(
select 'l1', 5
union all select 'l2', 12
union all select 'l3', 8
--union all select 'l4', 8
)
,boxes(box_id, capacity) AS
(
select 'o1',2
union all select 'o2', 8
union all select 'o3', 2
union all select 'o4', 5
union all select 'o5', 9
union all select 'o6', 5
)
,zx_numbers(zx_number) AS
(
--SELECT * FROM dbo.zx_numbers
--I have a dedicated numbers table on my machine, but I've substituted a
--manual sequence generator for the purposes of a self-contained demonstration
SELECT
(ones.n) + (10 * tens.n) + (100 * hundreds.n) AS zx_number
FROM --range 0 to 999
(VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS ones(n)
,(VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS tens(n)
,(VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS hundreds(n)
)
,items AS
(
SELECT
item_groups.*
,zx_number AS group_item_number
,ROW_NUMBER() OVER (ORDER BY item_group_id, zx_number) AS batch_item_number
FROM
item_groups
INNER JOIN
zx_numbers
ON (zx_number BETWEEN 1 AND item_groups.group_qty)
)
,box_slots AS
(
SELECT
boxes.*
,zx_number AS box_slot_number
,ROW_NUMBER() OVER (ORDER BY box_id, zx_number) AS batch_slot_number
FROM
boxes
INNER JOIN
zx_numbers
ON (zx_number BETWEEN 1 AND boxes.capacity)
)
,box_item_matches AS
(
SELECT
COALESCE(bxsl.batch_slot_number, itms.batch_item_number) AS slot_number
,bxsl.box_id
,bxsl.capacity
,bxsl.box_slot_number
,itms.item_group_id
,itms.group_qty
,itms.group_item_number
FROM
box_slots AS bxsl
FULL OUTER JOIN
items AS itms
ON (bxsl.batch_slot_number = itms.batch_item_number)
)
--SELECT * FROM box_item_matches
SELECT
box_id
,item_group_id
FROM
box_item_matches
GROUP BY
box_id, item_group_id
ORDER BY
IIF(box_id IS NULL OR item_group_id IS NULL, 1, 0) --i.e. NULLS LAST
,box_id
,item_group_id
Hallo aussehen sollte. Welche Version von SQL Server verwenden Sie? –
Hallo, SQL Server 2012 –
Dies fällt unter die Kategorie der so genannten "Eimer füllen" Probleme. Es ist eigentlich relativ einfach, rekursives SQL zu lösen. Wenn ich später eine Chance bekomme (und die Frage ist noch nicht beantwortet), werde ich den Code entwerfen und posten. Aus Gründen der Übersichtlichkeit: Wie groß ist die Gesamtzahl der Elemente, die pro Abfrageausführung behandelt werden müssen? Tausende oder Zig Millionen? – Steve