You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归CTE计算库存均价适配多Item问题求助

解决多Item下递归CTE计算库存均价的问题

问题背景

你现在遇到的情况很典型:单Item(比如2000045)时,递归CTE能正常从首个ReceiptNo开始计算初始均价,再递推后续的均价,但当表中有多个不同的Item No_及其对应的ReceiptNo时,查询就失效了——这是因为原来的CTE硬编码了特定Item,而且递归关联时没按Item分组,导致不同Item的计算逻辑串在了一起。

问题根源分析

看你原来的递归CTE代码,不管是锚点成员还是递归成员,都固定指定了A.[Item No_]='2000045',而且递归关联时只匹配了X.ReceiptNo = X1.ReceiptNo +1,没有关联Item No_,所以多Item时,不同Item的ReceiptNo会互相干扰,计算结果自然不对。

解决方案一:修改递归CTE支持多Item

我们可以调整CTE,让它对每个Item No_独立进行递归计算,不需要硬编码Item值,这也是性能最优的方案:

;WITH Testcte AS (
    -- 锚点成员:获取每个Item的第一个ReceiptNo(ReceiptNo=1)的初始均价
    SELECT 
        A.*,
        ((A.PurchaseQty * A.IntakeSellingPrice) + (A.InventoryBalance * ISNULL(A2.IntakeSellingPrice, A.IntakeSellingPrice))) / A.NewBalance AS [RunningAVG]
    FROM AKTest A
    LEFT JOIN AKTest A2 
        ON A.[Item No_] = A2.[Item No_] 
        AND A.ReceiptNo = A2.ReceiptNo + 1
    WHERE A.ReceiptNo = 1  -- 每个Item的起始记录
    
    UNION ALL
    
    -- 递归成员:基于同Item的上一个ReceiptNo的均价计算当前均价
    SELECT 
        X.*,
        ((X.PurchaseQty * X.IntakeSellingPrice) + (X.InventoryBalance * X1.RunningAVG)) / X.NewBalance AS [RunningAVG]
    FROM AKTest X
    JOIN Testcte X1 
        ON X.[Item No_] = X1.[Item No_]  -- 关键:按Item分组递归
        AND X.ReceiptNo = X1.ReceiptNo + 1
)
SELECT * FROM Testcte
ORDER BY [Item No_], ReceiptNo;  -- 按Item和ReceiptNo排序,方便查看

这个修改后的CTE会自动对每个Item No_单独处理,从各自的ReceiptNo=1开始递推,完全支持多Item场景。

解决方案二:使用游标遍历每个Item计算

如果因为某些特殊需求你需要用游标实现,这里是具体的代码示例:

-- 声明变量
DECLARE @ItemNo NVARCHAR(20);
DECLARE @ResultTable TABLE (
    IntakeSellingPrice DECIMAL(38,20),
    IntakeSellingAmount DECIMAL(38,6),
    [Item No_] NVARCHAR(20),
    [Posting Date] DATETIME,
    PurchaseQty DECIMAL(38,20),
    ReceiptNo BIGINT,
    InventoryBalance DECIMAL(38,20),
    NewBalance DECIMAL(38,20),
    RunningAVG DECIMAL(38,20)
);

-- 声明游标,遍历所有不同的Item No_
DECLARE ItemCursor CURSOR FOR
SELECT DISTINCT [Item No_] FROM AKTest;

-- 打开游标
OPEN ItemCursor;
FETCH NEXT FROM ItemCursor INTO @ItemNo;

-- 循环处理每个Item
WHILE @@FETCH_STATUS = 0
BEGIN
    -- 对当前Item执行递归CTE计算
    ;WITH Testcte AS (
        SELECT 
            A.*,
            ((A.PurchaseQty * A.IntakeSellingPrice) + (A.InventoryBalance * ISNULL(A2.IntakeSellingPrice, A.IntakeSellingPrice))) / A.NewBalance AS [RunningAVG]
        FROM AKTest A
        LEFT JOIN AKTest A2 
            ON A.[Item No_] = A2.[Item No_] 
            AND A.ReceiptNo = A2.ReceiptNo + 1
        WHERE A.ReceiptNo = 1 
          AND A.[Item No_] = @ItemNo
        
        UNION ALL
        
        SELECT 
            X.*,
            ((X.PurchaseQty * X.IntakeSellingPrice) + (X.InventoryBalance * X1.RunningAVG)) / X.NewBalance AS [RunningAVG]
        FROM AKTest X
        JOIN Testcte X1 
            ON X.[Item No_] = X1.[Item No_] 
            AND X.ReceiptNo = X1.ReceiptNo + 1
          AND X.[Item No_] = @ItemNo
    )
    -- 将当前Item的计算结果插入临时表
    INSERT INTO @ResultTable
    SELECT * FROM Testcte;

    -- 获取下一个Item
    FETCH NEXT FROM ItemCursor INTO @ItemNo;
END

-- 关闭并释放游标
CLOSE ItemCursor;
DEALLOCATE ItemCursor;

-- 输出所有结果
SELECT * FROM @ResultTable
ORDER BY [Item No_], ReceiptNo;

游标方案的思路是逐个取出每个Item No_,然后对单个Item执行原来的递归CTE计算,最后把所有结果汇总输出。不过要注意,游标在数据量较大时性能不如修改后的递归CTE,所以优先推荐第一种方案。

内容的提问来源于stack exchange,提问作者user3266033

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:18:02