我正在使用 SQL 层次结构数据类型在我的应用程序中对分类结构进行建模。 分类法在不同级别可以具有相同的名称
在设置过程中,需要通过 Excel 工作表上传此数据。
在插入任何节点之前,我想检查特定路径上的节点是否已存在,以便我不会重复条目。 检查节点@特定绝对路径是否已经存在的最简单方法是什么?
例如,在“Bank 2”下插入“Retail”之前,我应该能够检查“/Bank 2/Retail”不存在
有什么方法可以提供整个树结构的扁平化表示,以便我可以检查绝对路径然后继续?
是的,您可以使用递归 CTE。
在查询的每次迭代中,您可以附加层次结构名称的新级别。
互联网上有很多这种技术的示例。
例如,使用以下示例数据:
CREATE TABLE Test
(id INT,
parent_id INT null,
NAME VARCHAR(50)
)
INSERT INTO Test VALUES(1, NULL, 'L1')
INSERT INTO Test VALUES(2, 1, 'L1-A')
INSERT INTO Test VALUES(3, 2, 'L1-A-1')
INSERT INTO Test VALUES(4, 2, 'L1-A-2')
INSERT INTO Test VALUES(5, 1, 'L1-B')
INSERT INTO Test VALUES(6, 5, 'L1-B-1')
INSERT INTO Test VALUES(7, 5, 'L1-B-2')
你可以像这样编写递归 CTE:
WITH H AS
(
-- Anchor: the first level of the hierarchy
SELECT id, parent_id, name, CAST(name AS NVARCHAR(300)) AS path
FROM Test
WHERE parent_id IS NULL
UNION ALL
-- Recursive: join the original table to the anchor, and combine data from both
SELECT T.id, T.parent_id, T.name, CAST(H.path + '\' + T.name AS NVARCHAR(300))
FROM Test T INNER JOIN H ON T.parent_id = H.id
)
-- You can query H as if it was a normal table or View
SELECT * FROM H
WHERE PATH = 'L1\L1-A' -- for example to see if this exists
查询结果(没有where过滤器)如下所示:
1 NULL L1 L1
2 1 L1-A L1\L1-A
5 1 L1-B L1\L1-B
6 5 L1-B-1 L1\L1-B\L1-B-1
7 5 L1-B-2 L1\L1-B\L1-B-2
3 2 L1-A-1 L1\L1-A\L1-A-1
4 2 L1-A-2 L1\L1-A\L1-A-2
Google 把我带到这里来扁平化 HierarchyID。修改了 JotaBe 答案以使用 hierarchyid。
样本数据
CREATE TABLE #BankDemo
(
Node hierarchyid NOT NULL,
Name nvarchar(30) NOT NULL
);
INSERT #BankDemo
VALUES
('/1/', 'Bank1'),
('/2/', 'Bank2'),
('/1/1/', 'Retail'),
('/1/1/1/', 'Loans'),
('/1/1/2/', 'Advances'),
('/2/1/', 'Retail'),
('/2/1/1/', 'Agriculture Loans'),
('/2/1/2/', 'Advances');
递归查询
WITH H AS
(
-- Anchor: the first level of the hierarchy
SELECT Node, Node.ToString() as Path, Name, CAST(Name AS NVARCHAR(300)) AS FlattenedTreePath
FROM #BankDemo
WHERE Node.GetAncestor(1) = hierarchyid::GetRoot()
UNION ALL
-- Recursive: join the original table to the anchor, and combine data from both
SELECT T.Node, T.Node.ToString(), T.Name, CAST(H.FlattenedTreePath + '\' + T.Name AS NVARCHAR(300))
FROM #BankDemo T INNER JOIN H ON T.Node.GetAncestor(1) = H.Node
)
-- You can query H as if it was a normal table or View
SELECT * FROM H