SQL基于聚合总和返回有限的行

时间:2018-06-06 08:38:07

标签: sql sql-server

我想从一个表中返回多个行,其总和取决于另一个表中某行的值:

场景:特定商品数量的销售订单。该项目位于多个Bin位置。商店需要定向到最古老的材料。

我可以创建一个查询,列出Bin,bin中的数量并按年龄列出它们(最老到最年轻) - 到目前为止都很好,但是说订单是100个单位,有50个左右的单位在每个垃圾箱里有40个垃圾箱,然后我不想列出所有的垃圾箱,只列出最旧的垃圾箱 - 只需足以完成订单。

我该怎么做?

根据要求提供更多信息 DB = MS SQL 2016 样本数据: 以下是显示Bin的特定项目的数据,该bin中的数量和老化日期:

Bin#,Qty,Date

1,40,2018-05-15

3,45,2018-05-15

8,45,2018-02-10

12,45,2017-11-11

13,45,2018-02-10

15,45,2017-09-02

18,20,2017-09-02

销售订单是100个这样的项目,我们想选择FIFO(先进先出),所以我想要返回的结果是:

18,20,2017-09-02

15,45,2017-09-02

12,45,2017-11-11

这三个箱子共包含110个单位,足以满足销售订单。请注意,订单是日期,然后是数量

目前的实际查询是:

select 
    [OrderHed].[OrderNum] as [OrderHed_OrderNum],
    [OrderRel].[OrderLine] as [OrderRel_OrderLine],
    [Part].[PartNum] as [Part_PartNum],
    [Part].[PartDescription] as [Part_PartDescription],
    [OrderRel].[OurReqQty] as [OrderRel_OurReqQty],
    [PartBin].[BinNum] as [PartBin_BinNum],
    [PartBin].[OnhandQty] as [PartBin_OnhandQty],
    [PartLot].[FirstRefDate] as [PartLot_FirstRefDate]
from Erp.OrderHed as OrderHed
inner join Erp.OrderDtl as OrderDtl on 
    OrderHed.Company = OrderDtl.Company
    and OrderHed.OrderNum = OrderDtl.OrderNum
inner join Erp.OrderRel as OrderRel on 
    OrderDtl.Company = OrderRel.Company
    and OrderDtl.OrderNum = OrderRel.OrderNum
    and OrderDtl.OrderLine = OrderRel.OrderLine
    and ( OrderRel.OpenRelease = True  )

left outer join Erp.PartBin as PartBin on 
    OrderRel.Company = PartBin.Company
    and OrderRel.WarehouseCode = PartBin.WarehouseCode
    and ( not PartBin.BinNum like 'Q'  )

inner join Erp.Part as Part on 
    OrderDtl.Company = Part.Company
    and OrderDtl.PartNum = Part.PartNum
right outer join Erp.Part as Part
    and 
    PartBin.Company = Part.Company
    and PartBin.PartNum = Part.PartNum
inner join Erp.PartLot as PartLot on 
    PartBin.Company = PartLot.Company
    and PartBin.PartNum = PartLot.PartNum
    and PartBin.LotNum = PartLot.LotNum
where (OrderHed.OrderNum = @SalesOrder)
order by OrderDtl.OrderLine, PartLot.FirstRefDate, PartBin.OnhandQty

1 个答案:

答案 0 :(得分:0)

  1. 您可以选择日期小于或等于日期小于或等于的所有垃圾箱数量总和大于或等于目标数量的最小日期(例如50) )。

    SELECT *
           FROM bin b
           WHERE b.date <= (SELECT min(bb.date)
                                   FROM bin bb
                                   WHERE (SELECT sum(bbb.qty)
                                                 FROM bin bbb
                                                 WHERE bbb.date <= bb.date) >= 50)
    ORDER BY b.date,
             b.bin#;
    
    然而,这种方法可能包括比必要的更多的箱子。如果从最年轻的日期开始有更多的垃圾箱,那么只需要满足目标数量,所有垃圾箱都会被包含在内。因此,为订单挑选物品的人必须从这些垃圾箱中进行选择。但至少FIFO规则是这样保留的,而且无论如何都必须对物品进行计数,而不能盲目地从退回的箱子中挑选。

    SQL Fiddle(注意,我添加了bin 20来演示上述问题。)

  2. 如果您按日期订购所有垃圾箱,可以规避我提到的关于1.的问题。然后,与日期不会有重复的值。您可以在CTE中使用ROW_NUMBER()来引入此号码。然后从CTE中选择与1中相同的逻辑,但应用于行号而不是日期。

    WITH cte
    AS
    (
    SELECT ROW_NUMBER() OVER (ORDER BY b.date) row#,
           b.*
           FROM bin b
    )
    SELECT *
           FROM cte c
           WHERE c.row# <= (SELECT min(cc.row#)
                                   FROM cte cc
                                   WHERE (SELECT sum(ccc.qty)
                                                 FROM cte ccc
                                                 WHERE ccc.row# <= cc.row#) >= 50)
    ORDER BY c.date,
             c.bin#;
    

    SQL Fiddle(请注意,我再次添加了bin 20来证明,解决了1.中提到的问题。)

  3. 然而,这两种方法都不一定会产生最佳的&#34;箱子。例如,可能有一组具有正确日期的箱子,它们完全保留订购的物品数量,但这个集合只是偶然返回。可能还有一组基数的基数小于返回集的基数。