【问题标题】:CTE not updating all the selected rowsCTE 未更新所有选定的行
【发布时间】:2019-11-14 19:53:48
【问题描述】:

我正在尝试在 Inventory 上实现 FIFO。

我有以下与库存相关的表格:

Lot:
ID,SiteID,WHID,BatchID,Qty,Amount,QtyRemaning,AmountRemaning,LastQtyOut,DimComb, . . .

Dispatch Note:
ID,ProductID,SiteID,WHID,Quantity,DimComb, . . .

我有一个查询,它根据 FIFO 计算累计和 OUT 库存:

;WITH CTE AS (
    SELECT  
        DN.fldQty as DNQty,
        DN.fldProductID as DNProductID,
        lot.fldProductID as LotsProductID,
        lot.fldID as LotID,
        lot.fldQtyRemaning as QtyRemaning,
        lot.fldUnitCost as UnitCost,
        lot.fldQty as LotQty,
        lot.fldAmountRemaning as AmountRemaning,
        lot.fldLastQtyOut as LastQtyOut,
        lot.fldLastUpdateRefDoc as fldLastUpdateRefDoc,
        lot.fldLastUpdateRefDocNum as fldLastUpdateRefDocNum,
        DN.DimComb as DNDimComb,
        lot.DimComb,
        CumulativeSum= SUM(lot.fldQtyRemaning) 
        OVER 
        (PARTITION BY 
        DN.DimComb,
        lot.fldProductID,
        lot.fldSiteID,
        lot.fldWHID, 
        lot.fldLocationID,
        lot.fldPalletID--,
        --lot.fldBatchID 
        ORDER BY lot.fldID  ROWS UNBOUNDED PRECEDING) 
    FROM 
        #tmpTblDN DN
    RIGHT JOIN
        lot lot
    ON
        --lot.fldRefDocNum              =   tblGRNItems.fldGRNID                AND 
        ISNULL(DN.fldProductID,0) = ISNULL(lot.fldProductID,0) AND                              
        ISNULL(DN.fldSiteID,0)      =   ISNULL(lot.fldSiteID,0)         AND
        ISNULL(DN.fldWHID,0)        =   ISNULL(lot.fldWHID,0)           AND
        ISNULL(DN.fldLocationID,0)  =   ISNULL(lot.fldLocationID,0)     AND
        ISNULL(DN.fldPalletID,0)    =   ISNULL(lot.fldPalletID,0)       --AND
        --ISNULL(tblSIRItems.fldBatchID,0)    =   ISNULL(lot.fldBatchID,0)
    WHERE 
            DN.fldDNID              =       @DNID   
    AND     lot.fldQtyRemaning              >       0
)

UPDATE 
    CTE
SET
    QtyRemaning = CASE 

            WHEN (CumulativeSum - DNQty) < 0 AND DNProductID = LotsProductID THEN  0
            WHEN (CumulativeSum - DNQty) BETWEEN 0 AND QtyRemaning AND DNProductID = LotsProductID THEN (CumulativeSum - DNQty)
            ELSE QtyRemaning 
           END ,
    LastQtyOut = CASE 
            WHEN (CumulativeSum - DNQty) < 0 AND DNProductID = LotsProductID THEN QtyRemaning 
            WHEN (CumulativeSum - DNQty) BETWEEN 0 AND QtyRemaning AND DNProductID = LotsProductID THEN 
                CASE WHEN LotQty = QtyRemaning THEN
                    (QtyRemaning - (CumulativeSum - DNQty))
                ELSE
                    (CumulativeSum - (CumulativeSum - DNQty))
                END

            ELSE LastQtyOut 
           END ,
    AmountRemaning = CASE 
            WHEN (CumulativeSum - DNQty) < 0 AND DNProductID = LotsProductID THEN AmountRemaning - (QtyRemaning * UnitCost)
            WHEN (CumulativeSum - DNQty) BETWEEN 0 AND QtyRemaning AND DNProductID = LotsProductID THEN 
                CASE WHEN LotQty = QtyRemaning THEN
                    AmountRemaning - ((QtyRemaning - (CumulativeSum - DNQty)) * UnitCost)
                ELSE
                    AmountRemaning - ((CumulativeSum - (CumulativeSum - DNQty)) * UnitCost)
                END
            ELSE AmountRemaning 
           END ,
    fldDimComb = DNDimComb,
    fldLastUpdateRefDoc = 'DispatchNote',
    fldLastUpdateRefDocNum = @DNID

FROM CTE
WHERE CumulativeSum <= QtyRemaning + DNQty

现在我有相同的 ProductID 具有不同的数量和 DN 中不同的 DimComb 的情况,CTE 在选择时显示以下结果:

DNQty | DNProductID | LotsProductID | LotID | QtyRemaning | UnitCost | LotQty | AmountRemaning | LastQtyOut | CumulativeSum |
2     | 14          | 14            | 783   | 100         | 3        | 100    | 300            | NULL       | 100           |
3     | 14          | 14            | 783   | 100         | 3        | 100    | 300            | NULL       | 100           |

但问题是,它只用 DNQty 2 的第一行更新 Lot 表。

我还评论了 WHERE 子句,但它也不起作用。 我认为它没有用第二行(即 DNQty 3 的行)更新 Lot 表,因为这两行都引用 Lot 表中的同一行(即 LotID 783)。

任何帮助将不胜感激。

【问题讨论】:

  • 非常怀疑是否有人会穿过这堵代码墙开始调试它。但是我看到由于使用 where 子句而隐式转换为内部连接的右连接 - 这绝不是一个好兆头。使用脚本或小提琴提供简化示例将鼓励其他人。
  • 我在您的更新案例条件中看到:DNProductID =lotsProductID。但这并不像您在 CTE 中的连接那样考虑 NULL 值。那么,应该吗?还是您的 CTE 逻辑不一致且过于复杂?很大程度上取决于您的架构和表使用情况——只有您知道。
  • @SMor:感谢您花时间调查此事。我尽力提供尽可能多的信息来理解问题。对于 NULL check in update 语句,我已经在更新查询之前检查了 Lot 表的产品可用性。
  • 你的问题是意大利面条代码,语法的格式和一致性也有一些不足之处!

标签: sql-server common-table-expression fifo


【解决方案1】:

我认为它没有用第二行更新 Lot 表(即行 使用 DNQty 3),因为这两行都引用 Lot 表中的同一行 (即 LotID 783)。

是的,正是如此。

您的示例可以简化为:

create table #tmpTblDN (DNQty int, DNProductID int);
insert into #tmpTblDN values (2, 14), (3, 14);

create table #lot (LotsProductID int, 
                   LotID int, 
                   QtyRemaning int, 
                   UnitCost int, 
                   LotQty int, 
                   AmountRemaning int,
                   LastQtyOut int, 
                   CumulativeSum int);
insert into #lot values
(14, 783, 100, 3, 100, 300, NULL, 100)  


;WITH CTE AS 
(
    SELECT *
    FROM 
        #tmpTblDN DN
    RIGHT JOIN
        #lot lot
           on dn.DNProductID = lot.LotsProductID
)

UPDATE 
    CTE
SET
--select *,
    QtyRemaning = CASE 
            WHEN (CumulativeSum - DNQty) < 0 AND DNProductID = LotsProductID THEN  0
            WHEN (CumulativeSum - DNQty) BETWEEN 0 AND QtyRemaning AND DNProductID = LotsProductID THEN (CumulativeSum - DNQty)
            ELSE QtyRemaning 
           END 

FROM CTE
WHERE CumulativeSum <= QtyRemaning + DNQty

所以您清楚地看到您的第一个表包含 2 行,但您对只有一行的第二个表(通过 cte)执行 update

对此的解释可以在BOL文章UPDATE (Transact-SQL)“根据其他表中的数据更新数据”部分下找到:

在这种情况下,我想通过减去 DNQty 2 来更新 ID 为 783 的 Lot 和 3(即在第一次更新中 LotQtyRemaning 的值应为 98, 第二次更新后,它的值应该是 95)。

这意味着你想update你的Lot表使用DNQty的sum,所以首先你应该写一个聚合查询来计算sum(DNQty),这样你保证每个LotsProductID都会只有一个对应的DNProductID(在我的例子中。在你的例子中,你应该group by你在join中拥有的所有字段,而不是使用所有这些字段来join你的聚合结果到Lot表)

update lot
set QtyRemaning = CASE 
                    WHEN (CumulativeSum - DNQty) < 0 AND DNProductID = LotsProductID THEN  0
                    WHEN (CumulativeSum - DNQty) BETWEEN 0 AND QtyRemaning AND DNProductID = LotsProductID THEN (CumulativeSum - DNQty)
                    ELSE QtyRemaning 
                   END 
from #lot lot
     join (select DNProductID, sum(DNQty) as DNQty
           from #tmpTblDN
           group by DNProductID) dn
             on dn.DNProductID = lot.LotsProductID

【讨论】:

  • 非常感谢您的回复。对此,我真的非常感激。如果您提出一些解决方案/解决方法,这将非常有帮助。
  • 但是你的目标是什么?由于您对一行进行了一次更新,因此不清楚您希望得到什么结果。如果要将此行的值设置为最小值/最大值,则应在 cte 中使用聚合函数,如果要将其设置为“最后”值,请使用 cte 中的 row_number() 并按适当的顺序排列,然后使用“ where rn = 1" where rn = row_number() 在 cte 中定义
  • 我的目标是通过从各个批次的 QtyRemaning 列中减去 DN 数量来更新批次表。在这种情况下,我想通过减去 DNQty 2 和 3 来更新 ID 为 783 的 Lot(即在第一次更新中 LotQtyRemaning 的值应为 98,在第二次更新后它的值应为 95)。
  • @user2517610 我更新了我的答案,向您展示如何通过首先计算这些值的总和来减去更新中的多个值
猜你喜欢
  • 2013-03-12
  • 1970-01-01
  • 1970-01-01
  • 2021-05-29
  • 2011-11-13
  • 1970-01-01
  • 2014-10-10
  • 1970-01-01
  • 2018-01-24
相关资源
最近更新 更多