队列数量的SQL查询帮助

队列数量的SQL查询帮助,sql,sql-server,sql-server-2008,queue,Sql,Sql Server,Sql Server 2008,Queue,我有一个数据库,其中有一个订单表和库存表。 order items表有一个1条记录/1个数量布局,因此如果一个人下了7'ABC'和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 库存表具有每个位置的

我有一个数据库,其中有一个订单表和库存表。 order items表有一个1条记录/1个数量布局,因此如果一个人下了7'ABC'和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中我不是大师。
MSSQL 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。有时,由于数量或订单状态问题,订单可能无法拾取,但出于报告或分配目的,您仍希望在结果中显示这些订单。 :结束迭代


我感谢斯图尔特·安斯沃思的帮助,我只是想避免子查询和其他事情。我写这篇文章时,没有多次对同一个表进行任何连接,也没有子查询。撞了你的车,因为它太棒了

在order items表的示例中,qtyNum是每行增加,还是每行增加1。如果他们下了7项ABC的订单,看起来如果你把表加起来,就会显示28项为数量。还是我误解了qtyNum列的要点?提到物品的顺序只是额外的数据。它的类似项目id 10是该订单上项目“XYZ”的第三个数量。无论出于何种目的,我们都可以忽略qtynum这看起来太棒了!我一有几分钟的时间就会回顾这个解决方案。谢谢