Как написать рекурсивный запрос T-SQL для возврата иерархических данных, используя общую самосоединяющуюся таблицу для хранения данных дерева - PullRequest
0 голосов
/ 23 февраля 2019

Каждый раз, когда я пытаюсь вернуться к рекурсивным запросам, что редко, я чувствую, что начинаю заново, я ищу помощь в запросе данных из таблицы, в которой хранятся иерархические данные, с использованием обычного метода, имея таблицу для самостоятельного соединения.

Прежде всего, есть эта таблица, в которой хранятся «Группы», которые я называю «папками» с использованием аналогии с проводником Windows.Идентификатор - это 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

Во-вторых, существует таблица отношений, которая связывает группу с ее родительской группой.«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 Server, который возвращает имена всех групп, номер уровня рекурсии и идентификаторы для всех групп,Конечно, корень дерева будет иметь NULL ParentID и ParentName?

Например, эти поля будут в наборе результатов.

Level, GroupID, GroupName, ParentId, ParentName

Я понимаю, что существует несколько способов хранения данных этого типа.У меня нет гибкости, чтобы изменить дизайн БД.

В идеале, результат должен показывать все имена групп, даже корневой узел, у которого нет родителя.

Спасибо за любыепомощь

1 Ответ

0 голосов
/ 23 февраля 2019

Основываясь на последних данных, вы получите желаемый результат:

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;

db <> fiddle

Важно, чтобы вы понимали, как этоработает хоть.Как вы сказали в своем посте, вам, кажется, нужно каждый раз пересматривать их.Нет ничего плохого в том, что нужно что-то проверять синтаксис (есть вещи, которые я иногда с треском проваливаю при запоминании, особенно новые вещи OPENJSON), но понимаете ли вы, как это работает?Если нет, какой бит не так ли?

...