如何在SQL Server表中查找所有直接或间接子项的根父项?

时间:2016-06-28 19:39:40

标签: sql sql-server sql-server-2008 stored-procedures

我想在SQL Server中编写一个存储过程,使用此处的过程查找以下输出,子深度可以达到n级,我的要求是找到直接或间接连接到父级的所有子级的根父级:

Parent id child id      notes2
-----------------------------------
11000     12000         notes1
11000     12100         notes2
11000     12200 
11000     12250 
11000     12300 
11000     12350 
11000     13005 
11000     13006 
13000     13001 
13000     13002 
13000     13003 
13000     13004 
13000     13005 

我的表结构和数据是 -

CREATE TABLE [dbo].[parent_tbl]
(
    [parent_id] [nvarchar](50) NOT NULL,
    [description] [nvarchar](max) NULL,
    [notes] [nvarchar](max) NULL,

    CONSTRAINT [PK_parent_tbl] 
       PRIMARY KEY CLUSTERED ([parent_id] ASC)
)
GO

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'11000', N'item1', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'12000', N'item3', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'12100', N'item2', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'12200', N'item4', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'12250', N'item5', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'12300', N'item6', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'12350', N'item7', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'13000', N'item8', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'13001', N'item9', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES  (N'13002', N'item10', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'13003', N'item11', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'13004', N'item', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'13005', N'item', NULL)

INSERT [dbo].[parent_tbl] ([parent_id], [description], [notes]) 
VALUES (N'13006', N'a', NULL)


SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[child_tbl]
(
    [parent_id] [nvarchar](50) NOT NULL,
    [child_id] [nvarchar](50) NOT NULL,
    [notes2] [nvarchar](max) NULL
)
GO

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'11000', N'12000', N'notes1')

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'11000', N'12100', N'notes2')

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'11000', N'12200', NULL)

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'12200', N'12250', NULL)

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'12200', N'12300', NULL)

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'12300', N'12350', NULL)

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'13000', N'13001', NULL)

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'13001', N'13002', NULL)

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2])  
VALUES (N'13001', N'13003', NULL)

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'13004', N'13005', NULL)

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'12300', N'13005', NULL)

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'12200', N'13006', NULL)

INSERT [dbo].[child_tbl] ([parent_id], [child_id], [notes2]) 
VALUES (N'13001', N'13004', NULL)

1 个答案:

答案 0 :(得分:1)

recursive cte's对于检索分层数据非常有用

;WITH cte AS (
    SELECT  pt.parent_id,
            ct.notes2,
            ct.child_id
    FROM    [parent_tbl] pt
            JOIN [child_tbl] ct ON pt.parent_id = ct.parent_id
            LEFT JOIN [child_tbl] ct2 ON pt.parent_id = ct2.child_id
    WHERE   ct2.parent_id IS NULL -- only get parent id's that are not children
    UNION ALL
    SELECT  cte.parent_id,
            ct.notes2,
            ct.child_id
    FROM    cte
            JOIN [child_tbl] ct ON cte.child_id = ct.parent_id  
)
SELECT  parent_id, child_id, notes2 
FROM    cte 
ORDER BY parent_id, child_id