T-SQL查询的递归排序

T-SQL查询的递归排序,sql,tsql,sql-server-2008,Sql,Tsql,Sql Server 2008,根据下表 ID Path --------------------------------------- 1 \\Root 2 \\Root\Node0 3 \\Root\Node0\Node1 4 \\Root\Node0\Node2 5 \\Root\Node3 6 \\Root\Node3\Node4 7 \\Root\Node5 ... N \\Root\Node5\Node6\Node7\Node8\Node9\Node10 等等 这个表中大约有1

根据下表

ID    Path       
---------------------------------------
1  \\Root
2  \\Root\Node0
3  \\Root\Node0\Node1
4  \\Root\Node0\Node2
5  \\Root\Node3
6  \\Root\Node3\Node4
7  \\Root\Node5
...
N  \\Root\Node5\Node6\Node7\Node8\Node9\Node10
等等

这个表中大约有1000行。我想在单独的列中显示各个节点。显示的最大列数为5(即节点至5层深)。因此,输出 将如下所示

ID    Path           Level 0   Level 1  Level 2  Level 3  Level 4  Level 5
----------------------------------------------------------------------------------------
1  \\Root                    Root      Null     Null     Null     Null     Null
2  \\Root\Node0              Root      Node 0   Null     Null     Null     Null
3  \\Root\Node0\Node1        Root      Node 0   Node 1   Null     Null     Null
4  \\Root\Node0\Node2        Root      Node 0   Node 2   Null     Null     Null
5  \\Root\Node3              Root      Node 3   Null     Null     Null     Null
6  \\Root\Node3\Node4        Root      Node 3   Node 4   Null     Null     Null
7  \\Root\Node5              Root      Node 5   Null     Null     Null     Null
...
N  (see in above table)      Root      Node 5   Node 6   Node 7   Node 8 Node 9
我能想到的唯一方法是打开一个游标,循环每一行并执行字符串拆分,只需获取前5个节点,然后插入到临时表中

请建议


谢谢

您需要的是一个类似于以下内容的表值拆分函数:

CREATE FUNCTION [dbo].[udf_Split] (@DelimitedList nvarchar(max), @Delimiter nvarchar(2) = ',')
RETURNS @SplitResults TABLE (Position int NOT NULL PRIMARY KEY, Value nvarchar(max))
AS
Begin
    Declare @DelimiterLength int
    Set @DelimiterLength = DataLength(@Delimiter) / 2

    If Left(@DelimitedList, @DelimiterLength) <> @Delimiter
        Set @DelimitedList = @Delimiter + @DelimitedList

    If Right(@DelimitedList, @DelimiterLength) <> @Delimiter
        Set @DelimitedList = @DelimitedList + @Delimiter

    Insert @SplitResults(Position, Value)
    Select CharIndex(@Delimiter, A.list, N.Value) + @DelimiterLength            
        , Substring (
                    A.List
                    , CharIndex(@Delimiter, A.list, N.Value) + @DelimiterLength         
                    , CharIndex(@Delimiter, A.list, N.Value + 1)                            
                        - ( CharIndex(@Delimiter, A.list, N.Value) + @DelimiterLength ) 
                    )
    From dbo.Numbers As N
        Cross Join (Select @DelimitedList As list) As A
    Where N.Value > 0
        And N.Value < LEN(A.list)
        And Substring(A.list, N.Value, @DelimiterLength) = @Delimiter
    Order By N.Value

    Return
End

谢谢你,托马斯。那么我应该创建一个临时数字表吗?另外,数字表应该包含多少行?@stackoverflowuser-没有理由该表不能是永久的。数字表有很多用途,这只是其中之一。如果您注意到在Split函数中,它会根据字符串的长度进行过滤,因此numbers表应该至少与最大的字符串一样大。但是,10K行将占用很少的空间,应该足以满足您的需要。嗨,Thomas,我无法将“Path”(输入表中的列)作为输入传递给dbo.udf_Split。它给了我无效的列错误。“元素”列从何而来?谢谢。@stackoverflowuser-实际上,主要的疏忽是我键入了
交叉连接
,而不是
交叉应用
@stackoverflowuser-运行了一些测试并调整了答案。正如我前面提到的,我应该使用
交叉应用
。此外,为了使split函数能够很好地发挥作用,我们需要附加一个分隔符并删除额外的前导分隔符,这是我对post.SQL Server 2008 has hierarchyId()所做的。完全推荐。它支持一些有用的方法,比如GetLevel和getAsentor,它们可以一起用来解决这个问题。诚然,当它更改输入表模式时,这里的答案是欺骗:-)
With TableData As
    (
    Select 1 As Id, '\\Root' As [Path]
    Union Select All 2, '\\Root\Node0'
    Union Select All 3, '\\Root\Node0\Node1'
    Union Select All 4, '\\Root\Node0\Node2'
    Union Select All 5, '\\Root\Node3'
    Union Select All 6, '\\Root\Node3\Node4'
    Union Select All 7, '\\Root\Node5'
    )
    , SplitData As
    (
    Select T.Id, T.[Path], S.Value
        , Row_Number() Over ( Partition By T.Id Order By S.Position ) As Level
    From TableData As T
        Cross Apply dbo.udf_Split( (Substring(T.[Path],2,Len(T.[Path])) + '\') , '\') As S
    )
Select Id, [Path]
    , Min( Case When Level = 1 Then S.Value End ) As Level0
    , Min( Case When Level = 2 Then S.Value End ) As Level1
    , Min( Case When Level = 3 Then S.Value End ) As Level2
    , Min( Case When Level = 4 Then S.Value End ) As Level3
    , Min( Case When Level = 5 Then S.Value End ) As Level4
From SplitData As S
Group By Id, [Path]