تعليمات استعلام SQL لكميات قائمة الانتظار
-
06-07-2019 - |
سؤال
لدي قاعدة بيانات تحتوي على جدول الطلبات وجدول المخزون.
يحتوي جدول عناصر الطلب على سجل واحد لكل تخطيط كمية واحدة، لذلك إذا قدم شخص طلبًا لـ 7 'ABC's و4 'XYZ'، أحصل على 11 سجلًا في الجدول.
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
يحتوي جدول المخزون على تخطيط للكمية/العنصر لكل موقع، لذا يمكنني الحصول على 20 شيئًا في المخزون، ولكن يمكن أن يكون (في أسوأ الحالات) في 20 موقعًا منفصلاً.لذلك بالنسبة لمثالنا، قد يكون لدي المخزون التالي:
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
* ليس للحرفين H وJ أهمية خاصة!مجرد قيادة النقطة إلى المنزل أنهم الأحدث
يجب أن تقوم مجموعة النتائج بسحب أكبر عدد ممكن من المواقع الأقدم أولاً، لذلك في هذا المثال انتهى بي الأمر بـ "قائمة انتظار الاختيار" التالية:
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
لدي حل يتضمن الكثير من طرق العرض التي تم ضمها عدة مرات باستخدام الصلات الخارجية والأشياء المجنونة من هذا القبيل وأنا أشعر بالفضول فقط إذا كان هناك حل بسيط/أنيق لهذه المشكلة؟يمكنني أن أفعل ذلك بالكود دون أي مشكلة، لكن في SQL لست خبيرًا.
إم إس إس كيو إل 2008
المحلول
يا للعجب، كان هذا أمرًا صعبًا بالنسبة لي؛أنا متأكد من أن هناك حلول أكثر أناقة من هذا، ولكن هذا ما توصلت إليه:
--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
نصائح أخرى
بعد إعادة النظر في هذه المشكلة، قررت أنه سيكون أكثر كفاءة بكثير إنشاء دالة ذات قيمة جدولية و
الاستعلام كما هو الآن انتقل من 1:45 إلى 0:03.مذهل.
لسوء الحظ لا أستطيع نشر الكود، لكن الكود الزائف العام للحل هو:
قم بإنشاء متغير جدول ليحتوي على جميع مواقع الاختيار المتاحة والتي يمكن ربطها بأي شكل من الأشكال بأمر مفتوح.
قم بإنشاء متغير جدول ثانٍ ليحتوي على كافة الأوامر المفتوحة.قم بتضمين أي أعمدة تحتاجها لحالات العناصر الفردية في كل طلب.
قم بإنشاء جدول النتائج (أو قم بذلك أولاً، إذا كنت تستخدم دالة ذات قيمة جدولية) والذي يحتوي على المعلومات الضرورية لعملية الاختيار الخاصة بك.(لذا اطلب # و# العنصر و# والموقع الذي تريد سحبه منه.)
أعاد:
من عدد السجلات في الأوامر المفتوحة إلى 1 في جدول الأوامر المفتوحة، مع الانضمام إلى الموقع حيث الكمية > 0.قم بتخزين كل تمريرة في جدول النتائج.
قم بتقليل كمية الموقع الذي قمت بإدراجه للتو في جدول النتائج بمقدار 1، إذا كان لديك موقع.(في بعض الأحيان قد لا يكون الأمر قابلاً للانتقاء بسبب مشاكل الكمية أو العدالة ، لكنك ما زلت تريدها في نتائج أفعال التقارير أو التخصيص.): إنهاء التكرار
أقدر المساعدة التي قدمها ستيوارت أينسوورث، أردت فقط تجنب الاستعلامات الفرعية والأشياء.تمكنت من كتابة هذا دون القيام بأي صلة لنفس الجداول أكثر من مرة وبدون استعلامات فرعية.صدمتك لأنها رائعة جدًا!