生成用于 SQL Server hierarchyId 的唯一节点 ID

Posted

技术标签:

【中文标题】生成用于 SQL Server hierarchyId 的唯一节点 ID【英文标题】:Generating a unique node id for use with SQL Server hierarchyId 【发布时间】:2012-07-05 11:14:08 【问题描述】:

设置:

MyTable (
    NodeId varchar(10),
    ParentNodeId varchar(10),
    NodeName varchar(50)
)

NodeId 不是数字,可以采用任何形式。大多数是 Z123456 的形式,但有些是 12345。

我想使用 SqlServer HierarchyId 数据类型来满足我的分层需求。

问题:

我可以使用 CTE 生成具有节点和父级的层次结构,但我需要传递给 hierarchyid::Parse() 的路径 - 不幸的是,Z123456 形式的 nodeid 无法解析。如果 NodeId 和 ParentNodeId 是行 id 整数,我会收拾行李赶火车回家看我可爱的妻子,但相反,我在这里盯着 3360 x 1050 分辨率。

我正在使用 CTE 生成我的层次结构(我也可以在 CTE 中创建一个路径),然后我附加行号以提供我唯一的整数 ID,但我将不得不重新运行分层 CTE 使用生成的 Id 生成我的路径。

;with o as (
    select n.ParentNodeID, n.nodeid, n.NodeName, 1 as [level]
    from Mytable n where n.ParentNodeID is null
        union all
    select n.ParentNodeID, n.nodeid, n.NodeName, o.[level] + 1 as [Level]
    from MyTable n inner join o on n.ParentNodeID = o.NodeID
) 
select NodeID, ParentNodeID, NodeDescription
     , ROW_NUMBER() over (order by [level]) as hNodeId 
from o

问题:

无论如何,我是否可以通过一个 CTE 接受的表单 hierarchyId::Parse() 实现路径?例如/1/2/3/

TIA

【问题讨论】:

【参考方案1】:
with C as
(
  select T.NodeId,
         T.ParentNodeId,
         cast('/'+cast(row_number() over(order by T.NodeId) as varchar(10)) as varchar(max)) as HID
  from MyTable as T
  where T.ParentNodeId is null
  union all
  select T.NodeId,
         T.ParentNodeId,
         C.HID+'/'+cast(row_number() over(order by T.NodeId) as varchar(10))
  from MyTable as T
    inner join C 
      on T.ParentNodeId = C.NodeId
)
select NodeId,
       ParentNodeId,
       HID,
       hierarchyId::Parse(HID+'/') 
from C
order by HID

SQL-Fiddle

更新: 一些研究表明,不允许在递归 CTE 中使用分析函数。它在我的测试中有效,但如果我能想到替代解决方案,我会更新这个答案。

Omission about analytic and aggregate functions in CTEs

更新 2: 显然,这个解决方案可以安全使用,因为它记录在 MSDN 上。WITH common_table_expression (Transact-SQL)

CTE 递归部分中的分析和聚合函数是 应用于当前递归级别的集合而不是集合 对于 CTE。像 ROW_NUMBER 这样的函数只对 通过当前递归级别而不是全部传递给它们的数据 传递给 CTE 递归部分的数据集

【讨论】:

谢谢米凯尔。我正在做一些测试,因为我的层次结构非常深,产生了类似 /1/1/1/1/1/1/1/1/12 的路径 - 确保我可以获得祖先和后代。我正在考虑的一个解决方案是执行 Select *, row_number() .. as row from MyTable 进入 CTE,然后使用路径的“行”列对其进行递归 CTE,但我的递归 CTE 非常慢(结果集是〜25000行)。当我将此逻辑应用于我的代码时,我会更新。 不要使用 CTE 作为数据源进行递归 CTE。它非常慢,因为每次迭代都会重新生成第一个 CTE(带有 row_number)。如果您确实需要,最好使用临时表。 ParentNodeId 上的索引可以加快速度。

以上是关于生成用于 SQL Server hierarchyId 的唯一节点 ID的主要内容,如果未能解决你的问题,请参考以下文章

有哪些 GOOD 工具可用于从 SQL Server 数据库生成 ERD? [关闭]

ORM - 特定于用于 .NET 的 SQL Server 2008+

sql server 游标的知识

带有相关子查询的 While 循环的 SQL Server 性能调整

解析 SQL Server 数据库的脚本

如何生成唯一的server Id,server_id为何不能重复?