从自引用 table 获取 'root records'
Getting 'root records' from self-referencing table
我有一个自引用 table:有一个 ID 和一个 PARENTID 列,允许将记录按层次结构排序(我们称它们为记录层次结构)。
还有一个查询(我们称它为 'Query A'),return 是此 table 中的记录列表。一些 returned 记录是 'root records' (PARENTID = NULL),而一些是非根记录 (PARENTID != NULL)。请注意,'Query A' 可以 return 属于同一记录层次结构的多个记录。
我需要以最有效的方式完成(效率很重要但不是最重要的)是获取由 'Query A' 编辑的所有记录的根记录,以便非根记录在 'Query A' 中搜索它们的根记录。
如果要检索每个项目的 Root
项,则可以使用以下方法:
select t1.*,(case when t1.PARENTID is null then t1.ID else t1.PARENTID end ) Id_Root , 0 IsTraced into #tmp
from TableName t1
left outer join TableName t2 on t1.ID=t1.PARENTID
order by t1.PARENTID
while exists(select TOP 1 * , (select PARENTID from #tmp where ID=t1.PARENTID) Id_GrandParent from #tmp t1 where IsTraced=0 order by PARENTID desc )
begin
Declare @CurrentID as uniqueIdentifier
set @CurrentID = (select TOP 1 ID from #tmp t1 where IsTraced=0 order by PARENTID desc )
Declare @CurrentParentID as uniqueIdentifier
set @CurrentParentID = (select TOP 1 PARENTID from #tmp t1 where IsTraced=0 order by PARENTID desc )
Declare @CurrentGrandParentID as uniqueidentifier
set @CurrentGrandParentID=(select PARENTID from #tmp where ID=@CurrentParentID)
if(@CurrentGrandParentID is null)
begin
update #tmp set IsTraced=1 where ID=@CurrentID
end
else
begin
update #tmp set PARENTID= @CurrentGrandParentID, Id_Root=@CurrentGrandParentID where ID=@CurrentID
end
end
select ID,Id_Root
from #tmp
order by PARENTID
如您所见,在 while 循环之后,您可以从 Temp Table #tmp
中检索每个元素的 ID
和 Id_Root
可能的解决方案之一:
declare @TableA table
(
ID int,
ParentID int NULL,
Name varchar(100)
)
insert into @TableA(ID, ParentID, Name)
values
(1, NULL, 'root 1'),
(2, NULL, 'root 2'),
(3, 2, 'node 3->2'),
(4, 1, 'node 4->1'),
(5, 4, 'node 5->4->1'),
(6, 3, 'node 6->3->2'),
(7, 4, 'node 7->4->1'),
(8, 7, 'node 8->7->4->1')
;with QueryA as
(
/* your query could be here */
select t.ID, t.Name
from @TableA t
where t.ID in (1, 3, 8)
),
Tree as
(
select t.ID, t.ParentID, t.Name,
case when t.ParentID is NULL then t.ID end as RootID
from @TableA t
/* starting from rows we have in QueryA */
where t.ID in (select q.ID from QueryA q)
union all
select tt.ID, t.ParentID, t.Name,
case when t.ParentID is NULL then t.ID end as RootID
from @TableA t
/* recursion to parents */
inner join Tree tt on tt.ParentID = t.ID
)
select q.ID, q.Name, t.Name as RootName
from QueryA q
inner join Tree t on t.ID = q.ID and t.RootID is not NULL
order by 1, 2
您也可以从构建树开始而不链接到 QueryA(对于整个 table)。会显得简单一些。在这种情况下,您将仅在最终语句中引用 QueryA。
这是一道题吗?首先,每个记录只有一个父级。并且只有根记录具有空父值。因此,您不必做任何复杂的事情来获取根记录。
Select * from QueryA where PARENTID is null
在查询引擎对所有记录进行真正详尽的搜索h 之后,为您获取所有根记录! PARENTID 不为空的所有其他记录都不是根记录,根据定义它们是子记录。
我有一个自引用 table:有一个 ID 和一个 PARENTID 列,允许将记录按层次结构排序(我们称它们为记录层次结构)。
还有一个查询(我们称它为 'Query A'),return 是此 table 中的记录列表。一些 returned 记录是 'root records' (PARENTID = NULL),而一些是非根记录 (PARENTID != NULL)。请注意,'Query A' 可以 return 属于同一记录层次结构的多个记录。
我需要以最有效的方式完成(效率很重要但不是最重要的)是获取由 'Query A' 编辑的所有记录的根记录,以便非根记录在 'Query A' 中搜索它们的根记录。
如果要检索每个项目的 Root
项,则可以使用以下方法:
select t1.*,(case when t1.PARENTID is null then t1.ID else t1.PARENTID end ) Id_Root , 0 IsTraced into #tmp
from TableName t1
left outer join TableName t2 on t1.ID=t1.PARENTID
order by t1.PARENTID
while exists(select TOP 1 * , (select PARENTID from #tmp where ID=t1.PARENTID) Id_GrandParent from #tmp t1 where IsTraced=0 order by PARENTID desc )
begin
Declare @CurrentID as uniqueIdentifier
set @CurrentID = (select TOP 1 ID from #tmp t1 where IsTraced=0 order by PARENTID desc )
Declare @CurrentParentID as uniqueIdentifier
set @CurrentParentID = (select TOP 1 PARENTID from #tmp t1 where IsTraced=0 order by PARENTID desc )
Declare @CurrentGrandParentID as uniqueidentifier
set @CurrentGrandParentID=(select PARENTID from #tmp where ID=@CurrentParentID)
if(@CurrentGrandParentID is null)
begin
update #tmp set IsTraced=1 where ID=@CurrentID
end
else
begin
update #tmp set PARENTID= @CurrentGrandParentID, Id_Root=@CurrentGrandParentID where ID=@CurrentID
end
end
select ID,Id_Root
from #tmp
order by PARENTID
如您所见,在 while 循环之后,您可以从 Temp Table #tmp
ID
和 Id_Root
可能的解决方案之一:
declare @TableA table
(
ID int,
ParentID int NULL,
Name varchar(100)
)
insert into @TableA(ID, ParentID, Name)
values
(1, NULL, 'root 1'),
(2, NULL, 'root 2'),
(3, 2, 'node 3->2'),
(4, 1, 'node 4->1'),
(5, 4, 'node 5->4->1'),
(6, 3, 'node 6->3->2'),
(7, 4, 'node 7->4->1'),
(8, 7, 'node 8->7->4->1')
;with QueryA as
(
/* your query could be here */
select t.ID, t.Name
from @TableA t
where t.ID in (1, 3, 8)
),
Tree as
(
select t.ID, t.ParentID, t.Name,
case when t.ParentID is NULL then t.ID end as RootID
from @TableA t
/* starting from rows we have in QueryA */
where t.ID in (select q.ID from QueryA q)
union all
select tt.ID, t.ParentID, t.Name,
case when t.ParentID is NULL then t.ID end as RootID
from @TableA t
/* recursion to parents */
inner join Tree tt on tt.ParentID = t.ID
)
select q.ID, q.Name, t.Name as RootName
from QueryA q
inner join Tree t on t.ID = q.ID and t.RootID is not NULL
order by 1, 2
您也可以从构建树开始而不链接到 QueryA(对于整个 table)。会显得简单一些。在这种情况下,您将仅在最终语句中引用 QueryA。
这是一道题吗?首先,每个记录只有一个父级。并且只有根记录具有空父值。因此,您不必做任何复杂的事情来获取根记录。
Select * from QueryA where PARENTID is null
在查询引擎对所有记录进行真正详尽的搜索h 之后,为您获取所有根记录! PARENTID 不为空的所有其他记录都不是根记录,根据定义它们是子记录。