如何写T-SQL Recursive Query to return hierarchical data using common self-joining table to store tree data
How to write T-SQL Recursive Query to return hierarchical data using common self-joining table to store tree data
每次我尝试重新访问递归查询时,我都觉得我正在重新开始。我想从 table 中查询数据,该 table 使用通用方法存储分层数据,具有自连接的 table。
首先,table 存储“组”,我认为它是使用 Windows Explorer 类比的“文件夹”。 ID就是PK,还有关联的组名。
CREATE TABLE [dbo].[BPAGroup](
[id] [varchar](10) NOT NULL,
[name] [nvarchar](255) NOT NULL,
CONSTRAINT [PK_BPAGroup] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
其次也是最后一点,存在一种关系 table 将组与其父组相关联。 “GroupID”标识“MemberID”的组。例如,如果您将 BPAGroupGroup.MemberID 加入 [BPAGroup].ID,[BPAGroup].Name 将包含组的名称。如果你加入 BPAGroupGroup.GroupID 到 [BPAGroup].ID,[BPAGroup].Name 将包含 PARENT 组的名称。
CREATE TABLE [dbo].[BPAGroupGroup](
[memberid] [varchar](10) NOT NULL,
[groupid] [varchar](10) NOT NULL,
CONSTRAINT [PK_BPAGroupGroup] PRIMARY KEY CLUSTERED
(
[memberid] ASC,
[groupid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
-------------------------
ALTER TABLE [dbo].[BPAGroupGroup] WITH CHECK ADD CONSTRAINT [FK_BPAGroupGroup_BPAGroup_groupid] FOREIGN KEY([groupid])
REFERENCES [dbo].[BPAGroup] ([id])
GO
ALTER TABLE [dbo].[BPAGroupGroup] CHECK CONSTRAINT [FK_BPAGroupGroup_BPAGroup_groupid]
GO
ALTER TABLE [dbo].[BPAGroupGroup] WITH CHECK ADD CONSTRAINT [FK_BPAGroupGroup_BPAGroup_memberid] FOREIGN KEY([memberid])
REFERENCES [dbo].[BPAGroup] ([id])
GO
ALTER TABLE [dbo].[BPAGroupGroup] CHECK CONSTRAINT [FK_BPAGroupGroup_BPAGroup_memberid]
GO
下面是表单中的一些示例数据
Level1
Level2
Level3
和数据的SQL
INSERT [dbo].[BPAGroup] ([id], [name]) VALUES (N'A', N'Level1')
INSERT [dbo].[BPAGroup] ([id], [name]) VALUES (N'B', N'Level2')
INSERT [dbo].[BPAGroup] ([id], [name]) VALUES (N'C', N'Level3')
INSERT [dbo].[BPAGroupGroup] ([memberid], [groupid]) VALUES (N'B', N'A')
INSERT [dbo].[BPAGroupGroup] ([memberid], [groupid]) VALUES (N'C', N'B')
我如何编写递归 T-SQL 服务器查询 returns 所有组名称、递归“级别编号”和所有组的 ID。当然,树的根会有一个 NULL ParentID 和 ParentName?
例如,这些字段将在结果集中。
级别、GroupID、GroupName、ParentId、ParentName
我知道有多种方法可以存储这种类型的数据。我没有更改数据库设计的灵活性。
理想情况下,结果应显示所有没有父节点的组名,甚至是根节点。
根据最新数据,这似乎为您提供了您想要的结果:
WITH rCTE AS(
SELECT 1 AS Level,
id AS GroupID,
[name] AS GroupName,
CONVERT(nvarchar(10),NULL) AS ParentID, --This'll be uniqueidentifier in your real version
CONVERT(nvarchar(255),NULL) AS ParentName
FROM BPAGroup G
WHERE NOT EXISTS (SELECT 1
FROM BPAGroupGroup e
WHERE e.memberid = G.id)
UNION ALL
SELECT r.Level + 1,
G.id AS GroupID,
G.[name] AS GroupName,
r.GroupID AS ParentID,
r.[GroupName] AS ParentName
FROM BPAGroup G
JOIN BPAGroupGroup GG ON G.id = GG.memberid
JOIN rCTE r ON GG.groupid = r.GroupID)
SELECT *
FROM rCTE;
了解它的工作原理很重要。正如您在 post 中所说,您似乎每次都需要重新访问这些内容。需要检查某些东西的语法并没有错(有些东西我有时记不住,尤其是新的 OPENJSON
东西),但是你明白这是如何工作的吗?如果不是,你不喜欢哪一点?
每次我尝试重新访问递归查询时,我都觉得我正在重新开始。我想从 table 中查询数据,该 table 使用通用方法存储分层数据,具有自连接的 table。
首先,table 存储“组”,我认为它是使用 Windows Explorer 类比的“文件夹”。 ID就是PK,还有关联的组名。
CREATE TABLE [dbo].[BPAGroup](
[id] [varchar](10) NOT NULL,
[name] [nvarchar](255) NOT NULL,
CONSTRAINT [PK_BPAGroup] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
其次也是最后一点,存在一种关系 table 将组与其父组相关联。 “GroupID”标识“MemberID”的组。例如,如果您将 BPAGroupGroup.MemberID 加入 [BPAGroup].ID,[BPAGroup].Name 将包含组的名称。如果你加入 BPAGroupGroup.GroupID 到 [BPAGroup].ID,[BPAGroup].Name 将包含 PARENT 组的名称。
CREATE TABLE [dbo].[BPAGroupGroup](
[memberid] [varchar](10) NOT NULL,
[groupid] [varchar](10) NOT NULL,
CONSTRAINT [PK_BPAGroupGroup] PRIMARY KEY CLUSTERED
(
[memberid] ASC,
[groupid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
-------------------------
ALTER TABLE [dbo].[BPAGroupGroup] WITH CHECK ADD CONSTRAINT [FK_BPAGroupGroup_BPAGroup_groupid] FOREIGN KEY([groupid])
REFERENCES [dbo].[BPAGroup] ([id])
GO
ALTER TABLE [dbo].[BPAGroupGroup] CHECK CONSTRAINT [FK_BPAGroupGroup_BPAGroup_groupid]
GO
ALTER TABLE [dbo].[BPAGroupGroup] WITH CHECK ADD CONSTRAINT [FK_BPAGroupGroup_BPAGroup_memberid] FOREIGN KEY([memberid])
REFERENCES [dbo].[BPAGroup] ([id])
GO
ALTER TABLE [dbo].[BPAGroupGroup] CHECK CONSTRAINT [FK_BPAGroupGroup_BPAGroup_memberid]
GO
下面是表单中的一些示例数据
Level1
Level2
Level3
和数据的SQL
INSERT [dbo].[BPAGroup] ([id], [name]) VALUES (N'A', N'Level1')
INSERT [dbo].[BPAGroup] ([id], [name]) VALUES (N'B', N'Level2')
INSERT [dbo].[BPAGroup] ([id], [name]) VALUES (N'C', N'Level3')
INSERT [dbo].[BPAGroupGroup] ([memberid], [groupid]) VALUES (N'B', N'A')
INSERT [dbo].[BPAGroupGroup] ([memberid], [groupid]) VALUES (N'C', N'B')
我如何编写递归 T-SQL 服务器查询 returns 所有组名称、递归“级别编号”和所有组的 ID。当然,树的根会有一个 NULL ParentID 和 ParentName?
例如,这些字段将在结果集中。
级别、GroupID、GroupName、ParentId、ParentName
我知道有多种方法可以存储这种类型的数据。我没有更改数据库设计的灵活性。
理想情况下,结果应显示所有没有父节点的组名,甚至是根节点。
根据最新数据,这似乎为您提供了您想要的结果:
WITH rCTE AS(
SELECT 1 AS Level,
id AS GroupID,
[name] AS GroupName,
CONVERT(nvarchar(10),NULL) AS ParentID, --This'll be uniqueidentifier in your real version
CONVERT(nvarchar(255),NULL) AS ParentName
FROM BPAGroup G
WHERE NOT EXISTS (SELECT 1
FROM BPAGroupGroup e
WHERE e.memberid = G.id)
UNION ALL
SELECT r.Level + 1,
G.id AS GroupID,
G.[name] AS GroupName,
r.GroupID AS ParentID,
r.[GroupName] AS ParentName
FROM BPAGroup G
JOIN BPAGroupGroup GG ON G.id = GG.memberid
JOIN rCTE r ON GG.groupid = r.GroupID)
SELECT *
FROM rCTE;
了解它的工作原理很重要。正如您在 post 中所说,您似乎每次都需要重新访问这些内容。需要检查某些东西的语法并没有错(有些东西我有时记不住,尤其是新的 OPENJSON
东西),但是你明白这是如何工作的吗?如果不是,你不喜欢哪一点?