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

标签 sql sql-server t-sql common-table-expression

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

有一个表stktrans保存任何订单的INOUT交易。

当某些内容被发送OUT时,它将有一个IN_Nr,可用于追溯IN交易。 OrderNrIN链接到OUT

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

<表类=“s-表”> <标题> TransID 部分 IN_Nr OUT_Nr 订单号 类型 <正文> 8 123-1 232753 232233 888777 输出 7 123-1 232753 NULL 125707 IN 6 123-1 203944 224789 125707 输出 5 123-1 203944 NULL 123332 IN 4 123-1 179409 198306 123332 输出 3 123-1 179409 NULL 111222 IN 2 123-1 176573 171516 111222 输出 1 123-1 176573 NULL 666000 IN

回溯之间的节奏如下图:

Illustration

目前,我有一个非常非动态的查询,可以从任何给定的 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

关于sql - 递归 CTE 查询循环直到满足条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68080790/

相关文章:

sql - T-SQL MAX 函数替代方案

sql - 从 SQL Server 表中选择第 N 个最小元素

sql-server - 在我的条件中搜索带口音但不带口音的记录

javascript - 从 HTML 表到 mysql 数据库

sql - 使用 PowerShell 在 SQL Server 配置管理器中启用 TCP/IP

sql - Oracle:如何在表中的 USER_TABLES.TABLE_NAME 上添加外键

sql - 在 INNER JOIN 的一部分中使用 LIKE 子句

php - 具有两个图表系列的 Google 图表 (SQL/PHP)

sql-server - 使用带有临时表的存储过程的 BIML 生成 SSIS 包

.net - Elasticsearch和SQL Server进行全文搜索?