SQL获取Parent记录链
SQL Get Parent Record Chain
我有一个 table 像这样:
|ItemID|ItemName|ParentID|
|... etc more records ...|
|1234 |Itemlol |432 |
|... etc more records ...|
|1543 |Kthxhi |1234 |
|... etc more records ...|
|1938 |FunTimes|1543 |
|... etc more records ...|
|3765 |Apples |1938 |
|... etc more records ...|
|8634 |Oranges |3765 |
|... etc more records ...|
我可以在输入 3765 的地方进行查询并返回吗:
|1234 |Itemlol |432 |
|1543 |Kthxhi |1234 |
|1938 |FunTimes|1543 |
或者,甚至更好...还传入一个 "Number of Parents" 并返回那么多记录,因为可能有 30 条或更多条 parents,但我通常只需要 8 条。
我是等级制度的布道者。 HierarchyID 是 SQL 2008 年引入的一种不常用的数据类型,它编码层次结构。您拥有的数据是对层次结构进行编码的经典方法。也就是说,每条记录都有一个(可能为空)父 ID,指向 table 中的另一条记录。让我们逐步了解如何扩充您的数据。首先,一个沼泽标准递归通用table表达式(CTE):
create table #items (
ItemID int not null,
constraint PK_Items primary key clustered (ItemID),
Name nvarchar(100) not null,
ParentItemID int null,
constraint [FK_Items_Parent] foreign key
(ParentItemID) references #items (ItemID)
);
insert into #items (ItemID, Name, ParentItemID)
values
(1234 ,'Itemlol ', null ),
(1543 ,'Kthxhi ', 1234 ),
(1938 ,'FunTimes', 1543 ),
(3765 ,'Apples ', 1938 ),
(8634 ,'Oranges ', 3765 );
alter table #items add h hierarchyid null;
with cte as (
select ItemID, Name, ParentItemID, cast(concat('/', ItemID, '/') as varchar(1000)) as h
from #items
where ParentItemID is null
union all
select child.ItemID, child.Name, child.ParentItemID, cast(concat(parent.h, child.ItemID, '/') as varchar(1000)) as h
from #items as child
join cte as parent
on child.ParentItemID = parent.ItemID
)
update i
set h = cte.h
from #items as i
join cte
on i.ItemID = cte.ItemID;
请注意,我稍微更改了您的数据,以便有一个明确的递归锚点。我们在这里所做的是计算每一行的 hierarchyid 列应该具有的值。接下来,回答你的实际问题:
declare @h hierarchyid, @maxLevels tinyint = 2;
set @h = (select h from #items where ItemID = 3765);
select *
from #items as i
where @h.IsDescendantOf(i.h) = 1
and i.h.GetLevel() >= @h.GetLevel() - @maxLevels
and i.h <> @h;
请注意,我将其限制在被 return 编辑的层次结构中向上两个级别,因为您的数据太浅,无法显示实际上限制 return 集的八个级别。但是您需要做的就是在 运行 时将 @maxLevels
的值更改为 8,这样您就可以开始了。
编辑:由于您对经典的 CTE 方法表示了兴趣,这里有一种方法可以实现。本质上,您是在从子级到父级而不是从父级到子级遍历层次结构。不过,请根据您的实际数据在性能方面比较这两个解决方案!
declare @maxLevel tinyint = 2, @ItemID int = 3765;
with cte as (
select *, 0 as [level]
from #items
where ItemID = @ItemID
union all
select parent.*, child.level + 1 as [level]
from #items as parent
inner join cte as child
on child.ParentItemID = parent.ItemID
)
select *
from cte
where [level] <= @maxLevel
and ItemID <> @ItemID;
我有一个 table 像这样:
|ItemID|ItemName|ParentID|
|... etc more records ...|
|1234 |Itemlol |432 |
|... etc more records ...|
|1543 |Kthxhi |1234 |
|... etc more records ...|
|1938 |FunTimes|1543 |
|... etc more records ...|
|3765 |Apples |1938 |
|... etc more records ...|
|8634 |Oranges |3765 |
|... etc more records ...|
我可以在输入 3765 的地方进行查询并返回吗:
|1234 |Itemlol |432 |
|1543 |Kthxhi |1234 |
|1938 |FunTimes|1543 |
或者,甚至更好...还传入一个 "Number of Parents" 并返回那么多记录,因为可能有 30 条或更多条 parents,但我通常只需要 8 条。
我是等级制度的布道者。 HierarchyID 是 SQL 2008 年引入的一种不常用的数据类型,它编码层次结构。您拥有的数据是对层次结构进行编码的经典方法。也就是说,每条记录都有一个(可能为空)父 ID,指向 table 中的另一条记录。让我们逐步了解如何扩充您的数据。首先,一个沼泽标准递归通用table表达式(CTE):
create table #items (
ItemID int not null,
constraint PK_Items primary key clustered (ItemID),
Name nvarchar(100) not null,
ParentItemID int null,
constraint [FK_Items_Parent] foreign key
(ParentItemID) references #items (ItemID)
);
insert into #items (ItemID, Name, ParentItemID)
values
(1234 ,'Itemlol ', null ),
(1543 ,'Kthxhi ', 1234 ),
(1938 ,'FunTimes', 1543 ),
(3765 ,'Apples ', 1938 ),
(8634 ,'Oranges ', 3765 );
alter table #items add h hierarchyid null;
with cte as (
select ItemID, Name, ParentItemID, cast(concat('/', ItemID, '/') as varchar(1000)) as h
from #items
where ParentItemID is null
union all
select child.ItemID, child.Name, child.ParentItemID, cast(concat(parent.h, child.ItemID, '/') as varchar(1000)) as h
from #items as child
join cte as parent
on child.ParentItemID = parent.ItemID
)
update i
set h = cte.h
from #items as i
join cte
on i.ItemID = cte.ItemID;
请注意,我稍微更改了您的数据,以便有一个明确的递归锚点。我们在这里所做的是计算每一行的 hierarchyid 列应该具有的值。接下来,回答你的实际问题:
declare @h hierarchyid, @maxLevels tinyint = 2;
set @h = (select h from #items where ItemID = 3765);
select *
from #items as i
where @h.IsDescendantOf(i.h) = 1
and i.h.GetLevel() >= @h.GetLevel() - @maxLevels
and i.h <> @h;
请注意,我将其限制在被 return 编辑的层次结构中向上两个级别,因为您的数据太浅,无法显示实际上限制 return 集的八个级别。但是您需要做的就是在 运行 时将 @maxLevels
的值更改为 8,这样您就可以开始了。
编辑:由于您对经典的 CTE 方法表示了兴趣,这里有一种方法可以实现。本质上,您是在从子级到父级而不是从父级到子级遍历层次结构。不过,请根据您的实际数据在性能方面比较这两个解决方案!
declare @maxLevel tinyint = 2, @ItemID int = 3765;
with cte as (
select *, 0 as [level]
from #items
where ItemID = @ItemID
union all
select parent.*, child.level + 1 as [level]
from #items as parent
inner join cte as child
on child.ParentItemID = parent.ItemID
)
select *
from cte
where [level] <= @maxLevel
and ItemID <> @ItemID;