递归 CTE 查询循环直到满足条件

Recursive CTE query looping until conditions are met

我正在尝试编写一个查询,它将递归地寻找初始位置或部件号已更改。

有一个 table stktrans 保存任何订单的 INOUT 交易.

当发送某些东西时 OUT 它会有一个 IN_Nr 可以用来追溯 IN 事务。 OrderNrIN 链接到 OUT

编辑:给定任何 IN_Nr 我希望能够追溯到购买它的原始订单。在下面的 table 中 - TransID 1。但显示事件的完整时间线,例如下面的 table。

传输ID 部分 IN_Nr OUT_Nr 订单号 类型
8 123-1 232753 232233 888777 输出
7 123-1 232753 125707 输入
6 123-1 203944 224789 125707 输出
5 123-1 203944 123332 输入
4 123-1 179409 198306 123332 输出
3 123-1 179409 111222 输入
2 123-1 176573 171516 111222 输出
1 123-1 176573 666000 输入

回溯之间的规律如下图:

目前,我有一个非常非动态的查询,它可以从任何给定的 IN_Nr:

追溯 4 个级别

    DECLARE @IN_Nr INT = 232753
    
    
    ;WITH StkOUT_CTE AS (
            SELECT 
                ST.TransID, 
                ST.Part, 
                ST.IN_Nr, 
                ST.OUT_Nr,
                ST.OrderNr, 
                ST.Type
            FROM 
                StkTrans ST 
            WHERE
                OUT_Nr IS NOT NULL
                AND ST.Type = 'OUT'
    ),
    StkIN_CTE AS (
            SELECT 
                ST.TransID, 
                ST.Part, 
                ST.IN_Nr, 
                ST.OUT_Nr,
                ST.OrderNr, 
                ST.Type
            FROM 
                StkTrans ST 
                INNER JOIN StkOUT_CTE SI ON SI.IN_Nr = ST.IN_Nr
            WHERE
                ST.Type = 'IN'
    )
    SELECT 
           *
      FROM 
      (
              SELECT 
                1 RowOrder, *
              FROM 
              StkOUT_CTE  
              WHERE IN_Nr = @IN_Nr
          UNION
              SELECT 
                2 RowOrder, *
              FROM 
              StkIN_CTE
              WHERE IN_Nr = @IN_Nr
          UNION
            SELECT 3 RowOrder, *
            FROM 
                StkOUT_CTE
            WHERE
                OrderNr = (SELECT OrderNr FROM StkIN_CTE WHERE IN_Nr = @IN_Nr)
          UNION
            SELECT 4 RowOrder, *
            FROM 
                StkIN_CTE
            WHERE
                IN_Nr = (
                    SELECT IN_Nr
                    FROM 
                        StkOUT_CTE
                    WHERE
                        OrderNr = (SELECT OrderNr FROM StkIN_CTE WHERE IN_Nr = @IN_Nr))
        ) ST

要创建类似的设置:


    CREATE TABLE StkTrans (
        TransID INT, 
        Part VARCHAR(25), 
        IN_Nr INT, 
        OUT_Nr INT, 
        OrderNr INT, 
        Type    VARCHAR(3)
    )

    INSERT INTO StkTrans
    (TransID, Part, IN_Nr, OUT_Nr, OrderNr, Type)
    VALUES
    (1, '123-1', 176573, NULL, 666000, 'IN' ),
    (2, '123-1', 176573, 171516, 111222, 'OUT' ),
    (3, '123-1', 179409, NULL, 111222, 'IN' ),
    (4, '123-1', 179409, 198306, 123332, 'OUT' ),
    (5, '123-1', 203944, NULL, 123332, 'IN' ),
    (6, '123-1', 203944, 224789, 125707, 'OUT' ),
    (7, '123-1', 232753, NULL, 125707, 'IN' ),
    (8, '123-1', 232753, 232233, 888777, 'OUT' )

任何可能为我指明如何递归使用 CTE 的正确方向的指导都很棒!

字里行间,也许这就是您想要的?

WITH rCTE AS(
    SELECT *,
           1 AS Iteration
    FROM dbo.StkTrans ST
    WHERE ST.IN_Nr = '232753'
      AND ST.[Type] = 'IN'
    UNION ALL
    SELECT STi.*,
           r.Iteration + 1
    FROM dbo.StkTrans STo
         JOIN dbo.StkTrans STi ON STo.IN_Nr = STi.IN_Nr                     
         JOIN rCTE r ON STo.OrderNr = r.OrderNr
    WHERE STo.[Type] = 'Out'
      AND STi.[Type] = 'In')
SELECT TOP (1) TransID
FROM rCTE
ORDER BY ROW_NUMBER() OVER (ORDER BY Iteration DESC);

db<>fiddle


编辑: 也许这就是您所追求的。我现在也对 rCTE 中的第一个数据集进行参数化,以便于针对其他值进行测试。

DECLARE @IN_Nr int = 232753;

WITH rCTE AS(
    SELECT V.*,
           1 AS Iteration
    FROM dbo.StkTrans STo
         JOIN dbo.StkTrans STi ON STo.IN_Nr = STi.IN_Nr      
         CROSS APPLY (VALUES(STo.TransID,STo.Part,STo.IN_Nr,STo.OUT_Nr,STo.OrderNr,STo.[Type]),
                            (STi.TransID,STi.Part,STi.IN_Nr,STi.OUT_Nr,STi.OrderNr,STi.[Type]))V(TransID,Part,IN_Nr,OUT_Nr,OrderNr,[Type])
    WHERE STo.IN_Nr = @IN_Nr
      AND STo.[Type] = 'OUT'
      AND STi.[Type] = 'In'
    UNION ALL
    SELECT V.*,
           r.Iteration + 1
    FROM dbo.StkTrans STo
         JOIN dbo.StkTrans STi ON STo.IN_Nr = STi.IN_Nr                     
         JOIN rCTE r ON STo.OrderNr = r.OrderNr
                    AND r.[Type] = 'In'
         CROSS APPLY (VALUES(STo.TransID,STo.Part,STo.IN_Nr,STo.OUT_Nr,STo.OrderNr,STo.[Type]),
                            (STi.TransID,STi.Part,STi.IN_Nr,STi.OUT_Nr,STi.OrderNr,STi.[Type]))V(TransID,Part,IN_Nr,OUT_Nr,OrderNr,[Type])
    WHERE STo.[Type] = 'Out'
      AND STi.[Type] = 'In')
SELECT TransID,
       Part,
       IN_Nr,
       OUT_Nr,
       OrderNr,
       [Type]
FROM rCTE
ORDER BY TransID DESC;

db<>fiddle