Sql 在父子关系中使用hierarchyId
我有一个名为tb\u Section的表。它旨在支持n级层次结构。在父/子关系的情况下,每一行都有一个指向另一行的节ID的ParentSetionId 现在,我有一个过程,我必须将这些部分一个一个地复制到另一个表中,保持层次结构不变。我使用order by对该部分进行了如下安排:Sql 在父子关系中使用hierarchyId,sql,sql-server,Sql,Sql Server,我有一个名为tb\u Section的表。它旨在支持n级层次结构。在父/子关系的情况下,每一行都有一个指向另一行的节ID的ParentSetionId 现在,我有一个过程,我必须将这些部分一个一个地复制到另一个表中,保持层次结构不变。我使用order by对该部分进行了如下安排: Select s.SectionId, s.ParentSectionId, s.SectionName From tb_Section s Where s.TemplateId = 123 Order
Select
s.SectionId,
s.ParentSectionId,
s.SectionName
From
tb_Section s
Where
s.TemplateId = 123
Order By
Convert(hierarchyid, '/' + cast(sec.ParentSectionId as varchar)+ '/')
Super-Parent
Parent1
Child1
Child2
Parent2
Child3
Child4
我将这些插入一个表中,并将每个部分逐个插入另一个表中。这很好用。但在应用程序上线后,出现了一个问题
用户首先创建所有节作为父节,然后逐个编辑它们并使其成为其他节的子节(使用最困难的方式:/),节层次结构如下:
Select
s.SectionId,
s.ParentSectionId,
s.SectionName
From
tb_Section s
Where
s.TemplateId = 123
Order By
Convert(hierarchyid, '/' + cast(sec.ParentSectionId as varchar)+ '/')
Super-Parent
Parent1
Child1
Child2
Parent2
Child3
Child4
本例中的上述查询按顺序返回以下行
SuperParent
Child1
Child2
Parent1
Child3
Child4
Parent2
而不是正常情况,应该是这样
SuperParent
Parent1
Child1
Child2
Parent2
Child3
Child4
有什么帮助吗?我似乎找不到发生这种情况的原因
更新
下面是先插入子项的SQL脚本
CREATE TABLE tb_Section(
SectionId BIGINT NOT NULL PRIMARY KEY
,ParentSectionId BIGINT
,SectionName NVARCHAR(50) NOT NULL
);
INSERT INTO tb_Section(SectionId,ParentSectionId,SectionName) VALUES (SectionId,ParentSectionId,N'SectionName');
INSERT INTO tb_Section(SectionId,ParentSectionId,SectionName) VALUES (686772,686776,N'Child 1');
INSERT INTO tb_Section(SectionId,ParentSectionId,SectionName) VALUES (686773,686776,N'Child 2');
INSERT INTO tb_Section(SectionId,ParentSectionId,SectionName) VALUES (686774,686777,N'Child 3');
INSERT INTO tb_Section(SectionId,ParentSectionId,SectionName) VALUES (686775,686777,N'Child 4');
INSERT INTO tb_Section(SectionId,ParentSectionId,SectionName) VALUES (686776,686778,N'Parent 1');
INSERT INTO tb_Section(SectionId,ParentSectionId,SectionName) VALUES (686777,686778,N'Parent 2');
INSERT INTO tb_Section(SectionId,ParentSectionId,SectionName) VALUES (686778,NULL,N'Super-Parent');
这是我上面的查询返回的结果,带有hierarchyId
+-----------+-----------------+---------------+--------------+----------------+
| SectionId | ParentSectionId | SectionTypeId | SectionName | hierarchy |
+-----------+-----------------+---------------+--------------+----------------+
| 686778 | NULL | 1 | Super-Parent | NULL |
| 686772 | 686776 | 2 | Child 1 | 0xF800298C6620 |
| 686773 | 686776 | 2 | Child 2 | 0xF800298C6620 |
| 686774 | 686777 | 2 | Child 3 | 0xF800298C6660 |
| 686775 | 686777 | 2 | Child 4 | 0xF800298C6660 |
| 686776 | 686778 | 2 | Parent 1 | 0xF800298C66A0 |
| 686777 | 686778 | 2 | Parent 2 | 0xF800298C66A0 |
+-----------+-----------------+---------------+--------------+----------------+
您可以看到层次结构不同,在这里,子项显示在父项之前。我希望此示例数据有帮助。尝试使用递归CTE并创建自己的层次结构字符串:
;WITH Recurs
AS
(
SELECT SectionId, ParentSectionId,
SectionName, '/' + CAST(SectionId AS VARCHAR(MAX)) as Level
FROM tb_Section
WHERE ParentSectionId Is NULL
UNION ALL
SELECT s.SectionId, s.ParentSectionId, s.SectionName,
CAST(r.level + '/' + CAST(s.SectionId AS VARCHAR(MAX) )AS Varchar(MAX))
FROM tb_Section s
INNER JOIN recurs r
ON S.ParentSectionId = r.SectionId
)
SELECT *
FROM Recurs
ORDER BY Level
产生:
SectionId ParentSectionId SectionName Level
686778 NULL Super-Parent /686778
686776 686778 Parent 1 /686778/686776
686772 686776 Child 1 /686778/686776/686772
686773 686776 Child 2 /686778/686776/686773
686777 686778 Parent 2 /686778/686777
686774 686777 Child 3 /686778/686777/686774
686775 686777 Child 4 /686778/686777/686775
尝试使用递归CTE并创建自己的层次结构字符串:
;WITH Recurs
AS
(
SELECT SectionId, ParentSectionId,
SectionName, '/' + CAST(SectionId AS VARCHAR(MAX)) as Level
FROM tb_Section
WHERE ParentSectionId Is NULL
UNION ALL
SELECT s.SectionId, s.ParentSectionId, s.SectionName,
CAST(r.level + '/' + CAST(s.SectionId AS VARCHAR(MAX) )AS Varchar(MAX))
FROM tb_Section s
INNER JOIN recurs r
ON S.ParentSectionId = r.SectionId
)
SELECT *
FROM Recurs
ORDER BY Level
产生:
SectionId ParentSectionId SectionName Level
686778 NULL Super-Parent /686778
686776 686778 Parent 1 /686778/686776
686772 686776 Child 1 /686778/686776/686772
686773 686776 Child 2 /686778/686776/686773
686777 686778 Parent 2 /686778/686777
686774 686777 Child 3 /686778/686777/686774
686775 686777 Child 4 /686778/686777/686775
从您提供的数据来看,HierarchyID值在我看来不正确。运行此查询时:
CREATE TABLE tb_Section(
SectionId BIGINT NOT NULL PRIMARY KEY
,ParentSectionId BIGINT
,SectionName NVARCHAR(50) NOT NULL
, h HIERARCHYID
);
INSERT INTO [tb_Section]
( [SectionId], [ParentSectionId], [SectionName], [h] )
VALUES ( 686778, NULL, 'Super-Parent', NULL ),
( 686772, 686776, 'Child 1', 0xF800298C6620 ),
( 686773, 686776, 'Child 2', 0xF800298C6620 ),
( 686774, 686777, 'Child 3', 0xF800298C6660 ),
( 686775, 686777, 'Child 4 ', 0xF800298C6660 ),
( 686776, 686778, 'Parent 1 ', 0xF800298C66A0 ),
( 686777, 686778, 'Parent 2 ', 0xF800298C66A0 );
SELECT [ts].[SectionId] ,
[ts].[ParentSectionId] ,
[ts].[SectionName] ,
[ts].[h].ToString()
FROM [dbo].[tb_Section] AS [ts]
ORDER BY h
“Child N”值的值看起来不显示返回超级父级的任何连接。因此,让我们运行以下更新:
UPDATE [dbo].[tb_Section]
SET [h] = CONCAT('/686778', h.ToString())
WHERE [SectionName] LIKE 'Child%'
我们正在变得更好,但是现在如果我们再次运行上一步中的select,结果将基于层次深度返回。也就是说,超级父母首先回来,然后是父母,最后是孩子。当您查看层次结构的字符串值时,这仍然是有意义的;所有父行都具有相同的层次结构值,因此它们将一起排序
最后一次更新应该会让您到达您想要去的地方:
UPDATE [dbo].[tb_Section]
SET [h] = CONCAT(ISNULL(h.ToString(), '/'), [SectionId], '/')
现在,当您再次运行相同的选择时,子层次结构将被排序在一起。因此,TL;这个问题的关键在于,HierarchyID需要提供从源(在您的情况下为超级父级)到目标(在您的情况下为子级)的完整路径。根据您提供的数据,HierarchyID值在我看来不正确。运行此查询时:
CREATE TABLE tb_Section(
SectionId BIGINT NOT NULL PRIMARY KEY
,ParentSectionId BIGINT
,SectionName NVARCHAR(50) NOT NULL
, h HIERARCHYID
);
INSERT INTO [tb_Section]
( [SectionId], [ParentSectionId], [SectionName], [h] )
VALUES ( 686778, NULL, 'Super-Parent', NULL ),
( 686772, 686776, 'Child 1', 0xF800298C6620 ),
( 686773, 686776, 'Child 2', 0xF800298C6620 ),
( 686774, 686777, 'Child 3', 0xF800298C6660 ),
( 686775, 686777, 'Child 4 ', 0xF800298C6660 ),
( 686776, 686778, 'Parent 1 ', 0xF800298C66A0 ),
( 686777, 686778, 'Parent 2 ', 0xF800298C66A0 );
SELECT [ts].[SectionId] ,
[ts].[ParentSectionId] ,
[ts].[SectionName] ,
[ts].[h].ToString()
FROM [dbo].[tb_Section] AS [ts]
ORDER BY h
“Child N”值的值看起来不显示返回超级父级的任何连接。因此,让我们运行以下更新:
UPDATE [dbo].[tb_Section]
SET [h] = CONCAT('/686778', h.ToString())
WHERE [SectionName] LIKE 'Child%'
我们正在变得更好,但是现在如果我们再次运行上一步中的select,结果将基于层次深度返回。也就是说,超级父母首先回来,然后是父母,最后是孩子。当您查看层次结构的字符串值时,这仍然是有意义的;所有父行都具有相同的层次结构值,因此它们将一起排序
最后一次更新应该会让您到达您想要去的地方:
UPDATE [dbo].[tb_Section]
SET [h] = CONCAT(ISNULL(h.ToString(), '/'), [SectionId], '/')
现在,当您再次运行相同的选择时,子层次结构将被排序在一起。因此,TL;这一点的关键在于,HierarchyID需要提供从源(在您的情况下为超级父级)到目标(在您的情况下为子级)的完整路径。这里是一个很好的起点。一个原始表数据的示例很有用为什么不使用hierachyid类型@SteveFord的可能重复项我在order by语句中使用了hierarchyId,但是hierarchyId只有在数据插入树状表单时才能正常工作。在这里,叶节点首先作为父节点添加,然后更改为叶节点。一个原始表数据的示例很有用为什么不使用hierachyid类型@SteveFord的可能重复项我在order by语句中使用了hierarchyId,但是hierarchyId只有在数据插入树状表单时才能正常工作。在这里,叶节点首先作为父节点添加,然后更改为叶节点。谢谢。这个很好用。但就大数据而言,CTE不是很慢吗?@ZunairZubair对于大型查询来说可能很慢,如果你知道只有3个级别,那么你可以通过连接和UNIONSI的n级层次结构来实现同样的效果。但目前它工作正常。谢谢。这个很好用。但就大数据而言,CTE不是很慢吗?@ZunairZubair对于大型查询来说可能很慢,如果你知道只有3个级别,那么你可以通过连接和UNIONSI的n级层次结构来实现同样的效果。但它目前运行良好。