如何在 CTE 的所有递归行上提取相关的“锚”值

Posted

技术标签:

【中文标题】如何在 CTE 的所有递归行上提取相关的“锚”值【英文标题】:How to pull a related 'anchor' value on all recursive rows of a CTE 【发布时间】:2021-06-24 14:35:41 【问题描述】:

以以下网站为起点 (https://www.sqlservertutorial.net/sql-server-basics/sql-server-recursive-cte/) , 我做了一个 CTE 查询,如下所示:

    WITH q (n, Part_Number, Job, Material) AS (
SELECT
    0,
    Material.Part_Number,
    Material_Req.Job,
    Material_Req.Material
FROM 
    Production.dbo.Material_Req
    INNER JOIN PRODUCTION.dbo.Material ON Material_Req.Job = Material.Job
WHERE e.Job LIKE 'TEMPLATE%' AND e.Material IN  ('PART1')
UNION ALL
SELECT 
    n + 1,
    Material.Part_Number,
    Material_Req.Job,
    Material_Req.Material
FROM 
    Production.dbo.Material_Req
    INNER JOIN PRODUCTION.dbo.Material ON Material_Req.Job = Material.Job
    INNER JOIN q ON q.Material = Material.Material
    WHERE Material.Job LIKE 'TEMPLATE%')
SELECT DISTINCT n, Job, Part_Number, Material FROM q WHERE Job LIKE 'TEMPLATE%'
ORDER BY n

生成的结果如下表所示,相对易于导航,尤其是在最终用户知道内容的情况下。

n Job Part_Number Material
0 TEMP1 PART1 PART1a
0 TEMP1 PART1 PART1b
1 TEMP2 PART1a MATERIAL1
1 TEMP3 PART1b PART1b1
2 TEMP4 PART1b1 PART1b1a
3 TEMP5 PART1b1a MATERIAL2

但是,如果我要在锚点的 WHERE 条件中包含多个 PART,例如

WHERE e.Job LIKE 'TEMPLATE%' AND e.Material IN  ('PART1', 'PART2', ..., 'PART99')

生成的表格将难以导航。

我希望能够以某种方式附加递归行源自的原始锚“部分”。这甚至可能吗?我无法理解如何。结果表如下所示:

n Job Part_Number Material Anchor
0 TEMP1 PART1 PART1a PART1
0 TEMP1 PART1 PART1b PART1
0 TEMP8 PART2 PART2a PART2
1 TEMP2 PART1a MATERIAL1 PART1
1 TEMP3 PART1b PART1b1 PART1
1 TEMP9 PART2a PART2a1 PART2
2 TEMP4 PART1b1 PART1b1a PART1
2 TEMP10 PART2a1 MATERIAL7 PART2
3 TEMP5 PART1b1a MATERIAL2 PART1

【问题讨论】:

您可以使用相关表格中的任何可用列。所以你需要给with q (..., Material) as (...添加额外的列,定义为Material是锚select,然后再从q拉出来 【参考方案1】:

如果我理解正确,您只需在“上”SELECT 中暴露两次Part_Number 列,然后将CTE 的列放在“下”之一中:

WITH q AS
    (SELECT 0 AS n,
            Material.Part_Number,
            Material_Req.Job,
            Material_Req.Material,
            Material.Part_Number AS Anchor
     FROM Production.dbo.Material_Req
          INNER JOIN PRODUCTION.dbo.Material ON Material_Req.Job = Material.Job
     WHERE e.Job LIKE 'TEMPLATE%'
       AND e.Material IN ('PART1')
     UNION ALL
     SELECT n + 1,
            Material.Part_Number,
            Material_Req.Job,
            Material_Req.Material,
            q.Anchor
     FROM Production.dbo.Material_Req
          INNER JOIN PRODUCTION.dbo.Material ON Material_Req.Job = Material.Job
          INNER JOIN q ON q.Material = Material.Material
     WHERE Material.Job LIKE 'TEMPLATE%')
SELECT DISTINCT
       n,
       Job,
       Part_Number,
       Material,
       anchor
FROM q
WHERE Job LIKE 'TEMPLATE%'
ORDER BY n;

【讨论】:

q (n, Part_Number, Job, Material),所以它不应该有 anchor 列。还是我遗漏了一些特定于 T-SQL 的内容? 应该,我很少(从不)在我的WITH 子句中定义列,所以我错过了添加它,@astentx。相反,我给第一列一个别名,并在 WITH 中删除了别名 漂亮,非常感谢。 CTE 和 SQL 中的递归对我来说都是新的,所以我仍在尝试理解如何做不同的事情。太快了,我无法批准作为答案,哈哈

以上是关于如何在 CTE 的所有递归行上提取相关的“锚”值的主要内容,如果未能解决你的问题,请参考以下文章

通过递归 CTE 分解 BOM

表数据子集上的递归 CTE

递归 Cte 在 SQL 中查找 Min 和 Max 相关数据? [关闭]

通过 LEAD/LAG 或递归 CTE 更新?

递归 CTE - 查找经理下的所有员工

mysql递归查询cte