CTE 对祖父母的递归查询

CTE Recursive Query to Grandparents

我关注table:

ID NAME PARENT_ID ISDELETED ISINEDIT
1  JJ     NULL     1          0
2  AR     1        0          0
3 PR      2        0          0
4 DR      NULL     0          1

我需要得到的是 SELECT 查询,该查询将 return 只有具有 ISDELETED 0 和 ISINEDIT 0 且其 parents 或 grandparents 为 0 的行嗯

我目前有:

;WITH ChildParent AS
(
    SELECT
        a.id,
        a.name,
        a.isinedit,
        a.parent_id,
        a.isdeleted
    FROM dbo.table 
    WHERE isdeleted = 0 AND isinedit = 0 

    UNION ALL

    SELECT
        a.id,
        a.name,
        a.isinedit,
        a.parent_id,
        a.isdeleted
    FROM dbo.table a
    INNER JOIN ChildParent cp ON a.parent_id = cp.id
    WHERE a.isdeleted = 0  AND a.isinedit = 0
)
SELECT  
        id,
        name,
    parent_id,
        isinedit,
        isdeleted
FROM ChildParent

但由于某种原因,它 return 是双行

您需要将相同的 isdeleted = 0 AND isinedit = 0 谓词添加到 INNER JOIN childParent CP 来源。

...但是,如果您这样做,您的 CTE 查询就会非常繁琐,如果您必须一遍又一遍地重复同样的事情,那么可能有更好的方法。

...还有! SELECT 查询可以有多个 CTE 表达式:

;
WITH filtered AS
(
    SELECT
        a.id,
        a.name,
        a.parent_id,
    FROM
        dbo.Table
    WHERE
        IsDeleted = 0
        AND
        IsInEdit = 0 
)

WITH cte AS
(
    SELECT
        a.id,
        a.name,
        a.parent_id
    FROM
        filtered

    UNION ALL

    SELECT
        a.id,
        a.name,
        a.parent_id
    FROM
        filtered
        INNER JOIN cte ON a.parent_id = cte.id
)
SELECT  
    *
FROM
    cte
ORDER BY
    id

我认为这比您想象的要复杂一些。据我了解你的问题,你需要先遍历每个节点的整个 parent 层次结构,然后 然后 检查是否有任何 parent 不符合规则(你可以通过在 满足第一个 non-compliant parent 后停止 来稍微优化它。

您还需要跟踪原始节点,以便您可以在外部查询中进行适当的过滤(这避免了您当前获得的重复项)。

我会将您的查询表述为:

with cte as (
    select 
        t.*, 
        t.id original_id, 
        0 lvl, 
        1 is_ok
    from dbo.table t
    where isdeleted = 0 and isinedit = 0 
    union all
    select 
        t.*, 
        c.original_id, 
        c.lvl + 1, 
        case when t.isdeleted = 0 and t.isinedit = 0 then 1 else 0 end
    from dbo.table t
    inner join cte c on c.parent_id = t.id
    where c.is_ok = 1
)
select *
from cte c
where 
    c.lvl = 0
    and not exists (
        select 1 from cte c1 where c1.original_id = c.original_id and c1.is_ok = 0
    )

请注意,无论树中存在多少层,此查询都有效(如果层数超过 100 层,则需要在查询末尾添加 option(maxrecursion 0)

如果您先在 CTE 中创建干净的数据集,这些类型的查询会更容易。它摆脱了所有 CTE 查询中的额外过滤子句。

在这种情况下,return 所有未删除且不在编辑中的行。接下来是获取数据 Grand Parent INNER JOIN Parent INNER JOIN CHILD

;WITH GoodDataRows AS
(
    SELECT
        a.id,
        a.name,
        a.isinedit,
        a.parent_id,
        a.isdeleted
    FROM dbo.table 
    WHERE isdeleted = 0 AND isinedit = 0 
)
SELECT
  *
FROM GoodDataRows gp
  INNER JOIN GoodDataRows p ON p.parent_id = gp.id
  INNER JOIN GoodDataRows c on c.parent_id = p.id