我在 Microsoft SQL Server 中有
Product Categories
表:
类别ID(身份) | 节点(HIERARCHYID) | 类别名称 (NVARCHAR(100) |
---|---|---|
1 | 0x | 产品 |
2 | 0x58 | 主要类别1 |
3 | 0x68 | 主类2 |
4 | 0x5AC0 | 子类别 1A |
5 | 0x5B40 | 子类别 1B |
我想显示每个类别的面包屑,例如子类别 1A:
Products > Main Category 1 > Subcategory 1A
我是否使用递归 CTE,就好像存在自连接 (
ParentID
) 而不是 HIERARCHYID
,或者这与 HIERARCHYID
的工作方式不同吗?我在互联网上找到的所有有关面包屑的材料都假设使用 ParentID
,而不是 HIERARCHYID
。
您能给我举个例子吗?
谢谢你。
您将始终需要递归 CTE,除非您在创建或更新层次结构时预先计算面包屑。
您可以使用
.GetAncestor(1)
列上的 Node
获取家长 ID。
过滤 CTE,以便最终结果仅返回已递归到顶部的行。
WITH cte AS (
SELECT
t.*,
BreadCrumb = CAST(t.CategoryName AS nvarchar(max)),
ParentNode = t.Node.GetAncestor(1)
FROM YourTable t
UNION ALL
SELECT
cte.CategoryID,
cte.Node,
cte.CategoryName,
CONCAT(t.CategoryName, ' -> ', cte.BreadCrumb),
t.Node.GetAncestor(1)
FROM cte
JOIN YourTable t ON t.Node = cte.ParentNode
)
SELECT *
FROM cte
WHERE cte.ParentNode IS NULL;
鉴于您已经在使用hierarchyid,您拥有从给定类别一直向上返回层次结构所需的一切。首先,一个表值函数将给定的 Hierarchyid 分解为其所有组成部分:
create or alter function decomposeHierarchy(@h hierarchyid)
returns table
as
return
select h = @h.GetAncestor(n-1)
from dbo.Numbers as n
where n.n <= @h.GetLevel()+1;
go
其中
dbo.Numbers
只是一个从 1 开始的计数表。注意 - TVF 定义中的 ±1 是我的计数表从 1 开始而 GetLevel
是从 0 开始的结果。另请注意 - 如果您愿意,您可能可以使用 GENERATE_SERIES 而不是计数表。我过去还曾编写过一个小型 CLR 函数来进行此分解。
一旦我们有了分解层次结构的方法,将构成的层次结构ID连接回源数据并将它们连接在一起就很简单了。
declare @t table (
CategoryID int,
[Node] hierarchyid,
CategoryName varchar(100)
);
insert into @t
(CategoryID, [Node], CategoryName)
values
(1, 0x,'Products'),
(2, 0x58,'Main Category 1'),
(3, 0x68,'Main Category 2'),
(4, 0x5AC0,'Subcategory 1A'),
(5, 0x5B40,'Subcategory 1B');
declare @CategoryID int = 5;
declare @h hierarchyid = (
select [Node]
from @t
where CategoryID = @CategoryID
);
select STRING_AGG(CategoryName, ' > ') within group (order by c.[Node].GetLevel())
from dbo.decomposeHierarchy(@h) as d
join @t as c
on d.h = c.[Node];