Sql Server 2014 - 深度递归 Parent-Child 自连接
Sql Server 2014 - Deep Recursive Parent-Child Self Join
我正在尝试构建深度递归 self-join 查询。让 table 像:
Id | ParentId
1 | NULL
2 | 1
3 | 1
4 | 2
5 | 3
6 | 8
7 | 9
对于 Id 1,我的查询应该获取 1,2,3,4,5,因为它们要么是 1 的 children,要么是 1 的 children 的 children。在给定的示例中,查询结果中不应包含 6 和 7。
我尝试使用 CTE,但我收到大量重复项:
WITH CTE AS (
SELECT Id, ParentId
FROM dbo.Table
WHERE ParentId IS NULL
UNION ALL
SELECT t.Id, t.ParentId
FROM dbo.Table t
INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT * FROM CTE
想法?
使用 CTE
尝试以下查询,您可以通过 @parentID
设置 parentId:
DECLARE @parentID INT = 1
;WITH cte AS
(
SELECT
t.ID
, t.ParentId
FROM @table t
),
cteParent AS
(
SELECT
t.ID
, t.ParentId
FROM @table t
WHERE t.ParentId IN (SELECT t1.ID FROM @table t1 WHERE T1.ParentId = @parentID)
)
SELECT
DISTINCT c1.ID
, c1.ParentId
FROM cte c1
INNER JOIN cte c2 ON c2.ParentId = c1.ID
UNION ALL
SELECT *
FROM cteParent
样本数据:
DECLARE @table TABLE
(
ID INT
, ParentId INT
)
INSERT INTO @table
(
ID,
ParentId
)
VALUES
(1, NULL )
, (2, 1 )
, (3, 1 )
, (4, 2 )
, (5, 3 )
, (6, 8 )
, (7, 9 )
输出:
ID ParentId
1 NULL
2 1
3 1
4 2
5 3
您可以尝试使用DISTINCT
过滤重复的行。
;WITH CTE AS (
SELECT Id, ParentId
FROM T
WHERE ParentId IS NULL
UNION ALL
SELECT t.Id, t.ParentId
FROM T
INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT DISTINCT Id, ParentId
FROM CTE
试试这个 sql 脚本,结果是父子层次结构
;WITH CTE(Id , ParentId)
AS
(
SELECT 1 , NULL UNION ALL
SELECT 2 , 1 UNION ALL
SELECT 3 , 1 UNION ALL
SELECT 4 , 2 UNION ALL
SELECT 5 , 3 UNION ALL
SELECT 6 , 8 UNION ALL
SELECT 7 , 9
)
,Cte2
AS
(
SELECT Id ,
ParentId ,
CAST('\'+ CAST(Id AS VARCHAR(MAX))AS VARCHAR(MAX)) AS [Hierarchy]
FROM CTE
WHERE ParentId IS NULL
UNION ALL
SELECT c1.Id ,
c1.ParentId ,
[Hierarchy]+'\'+ CAST(c1.Id AS VARCHAR(MAX)) AS [Hierarchy]
FROM Cte2 c2
INNER JOIN CTE c1
ON c1.ParentId = c2.Id
)
SELECT Id,
RIGHT([Hierarchy],LEN([Hierarchy])-1) AS ParentChildHierarchy
FROM Cte2
GO
结果
Id ParentChildHierarchy
-------------------------
1 1
2 1
3 1
5 1
4 1
我没有看到重复项。
您的代码returns您提供的数据如下:
Id ParentId
1
2 1
3 1
5 3
4 2
这就是你想要的。
Here 是一个 db<>fiddle.
代码如下:
WITH t as (
SELECT *
FROM (VALUES (1, NULL), (2, 1), (3, 1), (4, 2), (5, 3), (6, 8), (7, 9)
) v(id, parentId)
),
CTE AS (
SELECT Id, ParentId
FROM t
WHERE ParentId IS NULL
UNION ALL
SELECT t.Id, t.ParentId
FROM t
INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT *
FROM CTE;
如果您在实际结果集中得到重复项,那么您可能在原始结果集中有重复项 table。我建议在 执行递归逻辑之前 删除它们:
with t as (
select distinct id, parentid
from <your query>
),
. . .
然后运行递归逻辑。
这个查询会对你有帮助
CREATE TABLE #table( ID INT, ParentId INT )
INSERT INTO #table(ID,ParentId)
VALUES (1, NULL ), (2, 1 ), (3, 1 ), (4, 2 ), (5, 3 ), (6, 8 ), (7, 9 )
;WITH CTE AS (
SELECT ID FROM #table WHERE PARENTID IS NULL
UNION ALL
SELECT T.ID FROM #table T
INNER JOIN #table T1 ON T.PARENTID =T1.ID
) SELECT * FROM CTE
我正在尝试构建深度递归 self-join 查询。让 table 像:
Id | ParentId
1 | NULL
2 | 1
3 | 1
4 | 2
5 | 3
6 | 8
7 | 9
对于 Id 1,我的查询应该获取 1,2,3,4,5,因为它们要么是 1 的 children,要么是 1 的 children 的 children。在给定的示例中,查询结果中不应包含 6 和 7。
我尝试使用 CTE,但我收到大量重复项:
WITH CTE AS (
SELECT Id, ParentId
FROM dbo.Table
WHERE ParentId IS NULL
UNION ALL
SELECT t.Id, t.ParentId
FROM dbo.Table t
INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT * FROM CTE
想法?
使用 CTE
尝试以下查询,您可以通过 @parentID
设置 parentId:
DECLARE @parentID INT = 1
;WITH cte AS
(
SELECT
t.ID
, t.ParentId
FROM @table t
),
cteParent AS
(
SELECT
t.ID
, t.ParentId
FROM @table t
WHERE t.ParentId IN (SELECT t1.ID FROM @table t1 WHERE T1.ParentId = @parentID)
)
SELECT
DISTINCT c1.ID
, c1.ParentId
FROM cte c1
INNER JOIN cte c2 ON c2.ParentId = c1.ID
UNION ALL
SELECT *
FROM cteParent
样本数据:
DECLARE @table TABLE
(
ID INT
, ParentId INT
)
INSERT INTO @table
(
ID,
ParentId
)
VALUES
(1, NULL )
, (2, 1 )
, (3, 1 )
, (4, 2 )
, (5, 3 )
, (6, 8 )
, (7, 9 )
输出:
ID ParentId
1 NULL
2 1
3 1
4 2
5 3
您可以尝试使用DISTINCT
过滤重复的行。
;WITH CTE AS (
SELECT Id, ParentId
FROM T
WHERE ParentId IS NULL
UNION ALL
SELECT t.Id, t.ParentId
FROM T
INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT DISTINCT Id, ParentId
FROM CTE
试试这个 sql 脚本,结果是父子层次结构
;WITH CTE(Id , ParentId)
AS
(
SELECT 1 , NULL UNION ALL
SELECT 2 , 1 UNION ALL
SELECT 3 , 1 UNION ALL
SELECT 4 , 2 UNION ALL
SELECT 5 , 3 UNION ALL
SELECT 6 , 8 UNION ALL
SELECT 7 , 9
)
,Cte2
AS
(
SELECT Id ,
ParentId ,
CAST('\'+ CAST(Id AS VARCHAR(MAX))AS VARCHAR(MAX)) AS [Hierarchy]
FROM CTE
WHERE ParentId IS NULL
UNION ALL
SELECT c1.Id ,
c1.ParentId ,
[Hierarchy]+'\'+ CAST(c1.Id AS VARCHAR(MAX)) AS [Hierarchy]
FROM Cte2 c2
INNER JOIN CTE c1
ON c1.ParentId = c2.Id
)
SELECT Id,
RIGHT([Hierarchy],LEN([Hierarchy])-1) AS ParentChildHierarchy
FROM Cte2
GO
结果
Id ParentChildHierarchy
-------------------------
1 1
2 1
3 1
5 1
4 1
我没有看到重复项。
您的代码returns您提供的数据如下:
Id ParentId
1
2 1
3 1
5 3
4 2
这就是你想要的。
Here 是一个 db<>fiddle.
代码如下:
WITH t as (
SELECT *
FROM (VALUES (1, NULL), (2, 1), (3, 1), (4, 2), (5, 3), (6, 8), (7, 9)
) v(id, parentId)
),
CTE AS (
SELECT Id, ParentId
FROM t
WHERE ParentId IS NULL
UNION ALL
SELECT t.Id, t.ParentId
FROM t
INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT *
FROM CTE;
如果您在实际结果集中得到重复项,那么您可能在原始结果集中有重复项 table。我建议在 执行递归逻辑之前 删除它们:
with t as (
select distinct id, parentid
from <your query>
),
. . .
然后运行递归逻辑。
这个查询会对你有帮助
CREATE TABLE #table( ID INT, ParentId INT )
INSERT INTO #table(ID,ParentId)
VALUES (1, NULL ), (2, 1 ), (3, 1 ), (4, 2 ), (5, 3 ), (6, 8 ), (7, 9 )
;WITH CTE AS (
SELECT ID FROM #table WHERE PARENTID IS NULL
UNION ALL
SELECT T.ID FROM #table T
INNER JOIN #table T1 ON T.PARENTID =T1.ID
) SELECT * FROM CTE