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
我关注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