【问题标题】:How to get recursivelevel using SQL Server 2012 hierarchyid?如何使用 SQL Server 2012 hierarchyid 获取递归级别?
【发布时间】:2017-05-17 05:24:21
【问题描述】:

我知道这很有挑战性,有没有 sql 专家请帮我解决这个问题。 我有hierarchyID 如下NameHID 列。它分别代表/NameID/dadID/MomID/。这意味着学生的父亲和母亲。我的表名是学生。

这是我的示例NAMEHID 专栏

/2/8/5/

/5/11/12/

/8/7/9/

我需要一个类似的输出

NameID   |  RecursiveLevel
2                 0
5                 1
7                 2
8                 1
9                 2
11                2
12                2

从这张图片中你可以看到什么是 RecursiveLevel。这棵树代表特定节点的祖先。


我只需要显示 NameID 和递归级别作为输出。 如果有任何其他附加信息需要这样做?

【问题讨论】:

  • 那...不是hierarchyid 的用途。
  • 我是 sql 新手。这是我的主管要求的任务之一。在这里,我提到了他给我的所有细节。这有什么不对吗?
  • 您显示的树自然会在 hierachyid 中表示为 /2//2/8//2/8/7//2/8/9/ 等值。这就是它的本意used - 每个 level 都通过在前一个 level 的末尾添加新值来表示。如果您使用该表示,调用GetLevel 并获得结果是微不足道的。不幸的是,这不是您正在使用的表示,因此这种数据类型的所有功能现在都将反对获得合理的结果。
  • @Damien_The_Unbeliever 感谢您提供的信息。现在我得到了关于hierachyid的明确信息。我们不能通过将上面的 NAMEHid 列作为主列的样本来完成这项任务吗?
  • 正如其他人所建议的那样,您的 HierarchyID 表示和树的图形表示不匹配。哪个是对的?输出似乎与图表匹配。如果是这种情况(即您正在尝试解决的情况),请告诉我,我可以提供帮助。

标签: sql sql-server hierarchyid


【解决方案1】:

您的数据不正确。 您可以使用拆分功能和recursive cte

来完成您的工作
DECLARE @SampleData TABLE
(
   NAMEHID varchar(30)
)

INSERT INTO @SampleData
(
   NAMEHID
)
VALUES
('/2/8/5/'),('/5/11/12/'),('/8/7/9/')

;with temp AS
(
   SELECT * FROM @SampleData sd
   CROSS APPLY
   (
      SELECT * FROM [dbo].[SplitString](STUFF(LEFT(sd.NameHID,LEN(sd.NameHID) - 1),1,1,''),'/')
   ) cr
)
,cte AS
(
   SELECT t.NameHID, t.[Value] , 0 AS Lvl FROM temp t
   WHERE t.Pos = 1
   AND NOT EXISTS ( 
                SELECT * FROM temp t2 
                WHERE  t2.[Value] = t.[Value] AND t2.Pos > 1
               )  -- root ID
   UNION ALL 

   SELECT t2.NameHID, t2.[Value], cte.Lvl + 1 
   FROM  cte 
   INNER JOIN temp t ON cte.[Value] = t.[Value] AND t.Pos = 1
   INNER JOIN temp t2 ON t.NameHID = t2.NameHID AND t2.Pos > 1
)
SELECT cte.[Value] AS NameId, cte.Lvl 
FROM cte 
ORDER BY cte.Lvl, cte.[Value]
OPTION(MAXRECURSION 0)

分割函数

CREATE FUNCTION [dbo].[SplitString] (@Text varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
   Select Pos = Row_Number() over (Order By (Select null))
        ,Value = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
   From (Select x = Cast('<x>'+ Replace(@Text,@Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A 
   Cross Apply x.nodes('x') AS B(i)
);

演示链接:http://rextester.com/KPX84657

【讨论】:

  • 感谢您的回答。我怀疑为什么我不能在 SELECT * FROM @SampleData sd 附近使用 where 子句?
  • 这是 where 子句 SELECT * FROM @SampleData sd where sd.NAMEHID &lt; 3 错误是 Incorrect syntax near the keyword 'CROSS'. Incorrect syntax near 'cr'.
  • 我认为 where 子句必须在 ) cr 之后。试试看。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-21
  • 1970-01-01
  • 2021-12-26
  • 2018-03-30
  • 2013-01-31
  • 2013-05-19
  • 1970-01-01
相关资源
最近更新 更多