Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
ElenaSTL
Starting Member
10 Posts |
Posted - 2014-10-24 : 12:33:15
|
Several years ago I had to create a report which shows on what week some orders will be fulfilled.This task appeared to be the most complex SQL task I ever had. I spent almost a week trying to make a code and the right decision came to my mind when I woke up at 2:00 am. The trick was to delete one or several lines from temp table and then insert back just one record in the same table with remaining value.The task:Company has some orders from internet and each order can have one or several items ordered. In my example I have 4 orders for 5,4,9,9 items. If they don’t have these items in the Warehouse, the order is becoming a backorder, so the company need to receive additional items from the manufacturer. Manufacturer is sending boxes with this item and one box may have enough items to fulfill several orders but, on the other hand one order could be fulfilled from several parcels. In my example we plan to receive boxes with 1,15,1,20 items on appropriate dates Feb. 1st 2012 and so on. Orders should be fulfilled in order they come, so the order 001 should be fulfilled before order 002. The Task was actually more complex and I had an outer loop for each Item and then grouped by weeks to show which orders will be fulfilled on which week and sort by Items with the biggest backorders amount.Here is my code just for one item. Maybe, somebody can propose a more original decision for this task.--table for Orders for one Item NumberDECLARE @OrdersTable table ( OrderNo varchar(20), OrderedQty int )--table for Supplies for one ItemNumberDECLARE @SupplyTable table ( PlanDate varchar(8), SupplyQty int )--table for Supplies for one ItemNumber with RunningTotal fieldDECLARE @RunningSumSupplyTable table ( PlanDate varchar(8), SupplyQty int, RunningTotal int )--Final TableDECLARE @FinalTable table ( OrderNo varchar(20), OrderedQty int, PlanDate varchar(8) )INSERT INTO @OrdersTable VALUES ('001', 5)INSERT INTO @OrdersTable VALUES ('002', 4)INSERT INTO @OrdersTable VALUES ('003', 9)INSERT INTO @OrdersTable VALUES ('004', 9)INSERT INTO @SupplyTable VALUES ('20120201', 1)INSERT INTO @SupplyTable VALUES ('20120202', 15)INSERT INTO @SupplyTable VALUES ('20120203', 1)INSERT INTO @SupplyTable VALUES ('20120204', 20)--calculate RunningTotal for @SupplyTable:INSERT INTO @RunningSumSupplyTable SELECT a.PlanDate, a.SupplyQty, SUM(b.SupplyQty) AS RunningTotal FROM @SupplyTable a CROSS JOIN @SupplyTable b WHERE (b.PlanDate <= a.PlanDate) GROUP BY a.PlanDate,a.SupplyQty ORDER BY a.PlanDate,a.SupplyQtyDECLARE @CurrentOrderNo varchar(20)DECLARE @CurrentOrderQty intSET @CurrentOrderQty = (SELECT TOP 1 OrderedQty FROM @OrdersTable)DECLARE @CurrentSupplyQty intDECLARE @CurrentPlanDate varchar(8) WHILE (SELECT count(*) FROM @OrdersTable) > 0 BEGIN SET @CurrentOrderNo = (SELECT TOP 1 OrderNo FROM @OrdersTable) SET @CurrentOrderQty = (SELECT TOP 1 OrderedQty FROM @OrdersTable) SET @CurrentSupplyQty = (SELECT TOP 1 RunningTotal FROM @RunningSumSupplyTable WHERE RunningTotal >= @CurrentOrderQty) SET @CurrentPlanDate = (SELECT TOP 1 PlanDate FROM @RunningSumSupplyTable WHERE RunningTotal >= @CurrentOrderQty) DELETE FROM @SupplyTable WHERE PlanDate <= @CurrentPlanDate INSERT INTO @SupplyTable VALUES (@CurrentPlanDate,@CurrentSupplyQty) UPDATE @SupplyTable SET SupplyQty = @CurrentSupplyQty - @CurrentOrderQty WHERE PlanDate = @CurrentPlanDate DELETE FROM @RunningSumSupplyTable --recalculate RunningTotal INSERT INTO @RunningSumSupplyTable SELECT a.PlanDate, a.SupplyQty, SUM(b.SupplyQty) AS RunningTotal FROM @SupplyTable a CROSS JOIN @SupplyTable b WHERE (b.PlanDate <= a.PlanDate) GROUP BY a.PlanDate,a.SupplyQty ORDER BY a.PlanDate,a.SupplyQty DELETE FROM @OrdersTable WHERE OrderNo = @CurrentOrderNo INSERT INTO @FinalTable VALUES (@CurrentOrderNo,@CurrentOrderQty,@CurrentPlanDate) ENDDELETE FROM @FinalTable WHERE PlanDate is nullSELECT * FROM @FinalTable |
|
ElenaSTL
Starting Member
10 Posts |
Posted - 2014-11-14 : 11:04:07
|
Another decision made by my friend S.T. using recursion:-- The real code would be more complicated - need to know what is in warehouse right now-- We assume our warehouse is empty and this is our first orders and supplies-- Create and populate original sample "order" tableCREATE TABLE #Order (ItemKey Int NOT NULL, OrderKey Int NOT NULL, OrderQty Int NOT NULL)INSERT INTO #Order VALUES (1, 1, 5)INSERT INTO #Order VALUES (1, 2, 4)INSERT INTO #Order VALUES (1, 3, 9)INSERT INTO #Order VALUES (1, 4, 9)INSERT INTO #Order VALUES (2, 5, 2)INSERT INTO #Order VALUES (2, 6, 7)INSERT INTO #Order VALUES (2, 7, 6)INSERT INTO #Order VALUES (2, 8, 3)INSERT INTO #Order VALUES (3, 5, 2)INSERT INTO #Order VALUES (3, 10, 3)INSERT INTO #Order VALUES (3, 11, 5)INSERT INTO #Order VALUES (3, 12, 8)--Create and populate original sample "supply" tableCREATE TABLE #Supply (ItemKey Int NOT NULL, DeliveryDate Datetime NOT NULL, DeliveryQty Int NOT NULL)INSERT INTO #Supply VALUES (1, '2012-02-01', 1)INSERT INTO #Supply VALUES (1, '2012-02-02', 15)INSERT INTO #Supply VALUES (1, '2012-02-03', 1)INSERT INTO #Supply VALUES (1, '2012-02-04', 20)INSERT INTO #Supply VALUES (2, '2012-02-05', 2)INSERT INTO #Supply VALUES (2, '2012-02-06', 17)INSERT INTO #Supply VALUES (2, '2012-02-07', 1)INSERT INTO #Supply VALUES (2, '2012-02-08', 10)INSERT INTO #Supply VALUES (3, '2012-02-09', 1)INSERT INTO #Supply VALUES (3, '2012-02-10', 14)INSERT INTO #Supply VALUES (3, '2012-02-11', 1)INSERT INTO #Supply VALUES (3, '2012-02-12', 1)-- Create and populate "order" working tableCREATE TABLE #OT (RowN Int NOT NULL, ItemKey Int NOT NULL, OrderKey Int NOT NULL, OrderQty Int NOT NULL)INSERT INTO #OT (RowN, ItemKey, OrderKey, OrderQty)SELECT ROW_NUMBER() OVER(PARTITION BY ItemKey ORDER BY OrderKey), ItemKey, OrderKey, OrderQty FROM #Order;WITH OrderTable(RowN, ItemKey, OrderKey, OrderQty) AS ( SELECT RowN, ItemKey, OrderKey, OrderQty FROM #OT WHERE RowN = 1 UNION ALL SELECT OT.RowN, OT.ItemKey, OT.OrderKey, O.OrderQty + OT.OrderQty FROM OrderTable O INNER JOIN #OT OT ON O.ItemKey = OT.ItemKey AND O.RowN + 1 = OT.RowN )UPDATE TSET T.OrderQty = O.OrderQtyFROM #OT T INNER JOIN OrderTable O ON T.RowN = O.RowN AND T.ItemKey = O.ItemKey AND T.Orderkey = O.OrderkeyOPTION (MAXRECURSION 0)-- Create and populate "supply" working tableCREATE TABLE #ST (RowN Int NOT NULL, ItemKey Int NOT NULL, DeliveryDate Datetime NOT NULL, DeliveryQty Int NOT NULL)INSERT INTO #ST (RowN, ItemKey, DeliveryDate, DeliveryQty)SELECT ROW_NUMBER() OVER(PARTITION BY ItemKey ORDER BY DeliveryDate), ItemKey, DeliveryDate, DeliveryQty FROM #Supply;WITH SupplyTable(RowN, ItemKey, DeliveryDate, DeliveryQty) AS ( SELECT RowN, ItemKey, DeliveryDate, DeliveryQty FROM #ST WHERE RowN = 1 UNION ALL SELECT ST.RowN, ST.ItemKey, ST.DeliveryDate, S.DeliveryQty + ST.DeliveryQty FROM SupplyTable S INNER JOIN #ST ST ON S.ItemKey = ST.ItemKey AND S.RowN + 1 = ST.RowN )UPDATE TSET T.DeliveryQty = S.DeliveryQtyFROM #ST T INNER JOIN Supplytable S ON T.RowN = S.RowN AND T.ItemKey = S.ItemKey AND T.DeliveryDate = S.DeliveryDateOPTION (MAXRECURSION 0)-- Create and populate final table. Needed for cases when more then one kind of item in the same orderCREATE TABLE #FinalTable (ItemKey Int NOT NULL, OrderKey Int NOT NULL, OrderQty Int NOT NULL, ShippingDate Datetime NULL)INSERT INTO #FinalTable (ItemKey, OrderKey, OrderQty, ShippingDate)SELECT O.ItemKey, O.OrderKey, O.OrderQty, MIN(ST.DeliveryDate) ShippingDateFROM #Order O LEFT JOIN #OT OT ON O.ItemKey = OT.ItemKey AND O.OrderKey = OT.OrderKey LEFT JOIN #ST ST ON OT.ItemKey = ST.ItemKey AND OT.OrderQty <= ST.DeliveryQtyGROUP BY O.ItemKey, O.OrderKey, O.OrderQty--Final SELECTSELECT Orderkey, SUM(OrderQty) OrderQty, MAX(ShippingDate) ShippingDate, CASE WHEN COUNT(*) = 1 AND MAX(ShippingDate) IS NOT NULL THEN 'Your item(s) will be shipped on ' + CONVERT(Varchar(25), MAX(ShippingDate), 101) WHEN COUNT(*) > 1 AND MAX(ShippingDate) IS NOT NULL THEN 'We will ship your items in one package on ' + CONVERT(Varchar(25), MAX(ShippingDate), 101) WHEN MAX(ShippingDate) IS NULL THEN 'Your item is on backorder. We will notify you when it''s available.' ELSE 'Please contact us for more information' END MessageFROM #FinalTableGROUP BY OrderKeyORDER BY OrderKey, OrderQtyDROP TABLE #OrderDROP TABLE #SupplyDROP TABLE #OTDROP TABLE #STDROP TABLE #FinalTable |
|
|
|
|
|
|
|