SQL Update - 按顺序提交每一行

时间:2011-06-06 12:00:40

标签: sql sql-server sql-server-2005

早上好。我会尽力解释我的问题而不发布SQL(它是650行)。如果需要更多信息,请告诉我。

我们有一个内部履行系统,可以实时分配库存。为了使分配正常工作,我们需要知道每次用户询问他们应该处理什么时(通过加载/重新加载他们的任务列表)可用的库存量。数据看起来像这样:

ID    ItemID    QtyOrdered    QtyAvailableAfterAllocation    ParentID
1     1234      5             500                            NULL
2     1234      15            485                            1
3     1234      10            475                            2

目前正在使用while循环来设置 QtyAvailableAfterAllocation 列。上面的例子演示了对循环的需求。第2行的QtyAvailableAfterAllocation依赖于第1行的QtyAvailableAfterAllocation的值。第3行依赖于第2行,依此类推。

这是逻辑的(非常)简化版本。考虑到套件(属于单个父项的库存项目组)时,它会变得无比复杂。有时库存不需要分配到物料,因为它存在于具有足够库存以完成订单的工具箱内。这就是为什么我们不能做总计。此外,套件可以嵌套在第N级套件内。这就是问题所在。处理大量具有嵌套套件的订单时,查询的性能非常差。我相信循环是罪魁祸首(测试证明了这一点)。所以,这是问题:

是否可以提交更新,一次一行并按特定顺序(没有循环),以便下面的子记录可以访问父记录中的更新列(QtyAvailAfterOrder_AllocationScope)? / p>

修改

这是SQL的一小部分。这是实际的while循环。也许这将有助于显示确定每条记录分配所需的逻辑。

http://pastebin.com/VM9iasq9

4 个答案:

答案 0 :(得分:1)

你能欺骗并做这样的事吗?

DECLARE @CurrentCount int
SELECT @CurrentCount = QtyAvailableAfterAllocation 
FROM blah 
WHERE <select the parent of the first row>

UPDATE blah
SET QtyAvailableAfterAllocation = @CurrentCount - QtyOrdered,
    @CurrentCount = @CurrentCount - QtyOrdered
WHERE <it is valid to deduct the count>

这应该允许您保持基于设置的更新并从起始数量向下计数。这里问题的关键是WHERE条款。

我们一直在做的一种方法是将值的层次结构(在您的情况下,第N个工具包的想法)展平成表,然后您可以加入此平面表。层次结构和单一连接的扁平化应该有助于缓解一些性能怪癖。也许使用视图来展平数据。

对不起,这不是一个直接的答案,只是一些想法。

如果您可以提供样本数据结构来展示这些工具包的适用性,我相信有人可以帮助您提供更具体的解决方案。

答案 1 :(得分:0)

如果您确实在某些结构中排队了请求,则不会使用SQL语句来处理队列;从概念上讲,“队列”和“SQL”是不一致的:SQL是基于集合的,而不是程序性的。

因此,忘记使用查询来管理排队的请求,并在一个过程中处理队列,将每个部件申请包装在一个事务中:

        pseudo:
        WHILE REQUESTS_REMAIN_IN_QUEUE

             begin trans
                execute requisition SQL statements
             commit

        LOOP

您的申请单(简化)可能如下所示:

           update inventory
           set QOH = QOH- {requested amount}
           where  partno = ? and QOH >= {requested amount}

           insert orderdetail
           (customer, orderheaderid, partno, requestedamount)
           values
           (custid, orderheaderid, partno, requested_amount)

现在,在涉及工具包和自定义业务逻辑的复杂系统中,如果工具包中的每个组件都不可用,您可能会有一条规则,即不会减少库存。然后,如果您遇到工具包中的单个组件需要延期交货的情况,那么您必须在交易中回滚工具包申请并回滚。

答案 2 :(得分:0)

我认为这个问题可以通过纯粹的基于集合的方法来解决。

基本上,您需要执行以下步骤:

  1. 获取每个项目的当前可用数量表。

  2. 从要处理的订购数量中获取运行总计。

  3. 为每个项目获取QtyAvailableAfterAllocation作为从其可用数量中减去其运行总计的结果。

  4. 以下是一个示例解决方案:

    /* sample data definition & initialisation */
    DECLARE @LastQty TABLE (Item int, Qty int);
    INSERT INTO @LastQty (Item, Qty) 
      SELECT 0123, 404 UNION ALL
      SELECT 1234, 505 UNION ALL
      SELECT 2345, 606 UNION ALL
      SELECT 3456, 707 UNION ALL
      SELECT 4567, 808 UNION ALL
      SELECT 5678, 909;
    DECLARE @Orders TABLE (ID int, Item int, OrderedQty int);
    INSERT INTO @Orders (ID, Item, OrderedQty)
      SELECT 1, 1234,  5 UNION ALL
      SELECT 2, 1234, 15 UNION ALL
      SELECT 3, 2345,  3 UNION ALL
      SELECT 4, 1234, 10 UNION ALL
      SELECT 5, 2345, 37 UNION ALL
      SELECT 6, 2345, 45 UNION ALL
      SELECT 7, 3456, 50 UNION ALL
      SELECT 8, 4567, 25 UNION ALL
      SELECT 9, 2345, 30;
    
    /* the actuall query begins here */
    WITH RankedOrders AS (
      SELECT
        *,
        rn = ROW_NUMBER() OVER (PARTITION BY Item ORDER BY ID)
      FROM @Orders
    ),
    RunningOrderTotals AS (
      SELECT
        ID,
        Item,
        OrderedQty,
        RunningTotalQty = OrderedQty,
        rn
      FROM RankedOrders
      WHERE rn = 1
      UNION ALL
      SELECT
        o.ID,
        o.Item,
        o.OrderedQty,
        RunningTotalQty = r.RunningTotalQty + o.OrderedQty,
        o.rn
      FROM RankedOrders o
        INNER JOIN RunningOrderTotals r ON o.Item = r.Item AND o.rn = r.rn + 1
    )
    SELECT
      t.ID,
      t.Item,
      t.OrderedQty,
      QtyAvailableAfterAllocation = oh.Qty - t.RunningTotalQty
    FROM RunningOrderTotals t
      INNER JOIN @LastQty oh ON t.Item = oh.Item
    ORDER BY t.ID;
    

    注意:出于我的示例的目的,我手动初始化了可用的项目数量表(@LastQty)。但是,您很可能会从您的数据中获取它。

答案 3 :(得分:0)

根据上面的评论/答案以及我无法正确准确地表示这个复杂的问题,我已经用C#重写了处理。使用PLINQ,我将处理时间从15秒缩短到4.感谢所有试图帮助的人!

如果这不是关闭问题的合适方式,请告诉我(并告诉我相应的方式,以便我可以这样做)。