2010-06-16 6 views
1

Basé sur le tableau suivantsorte récursive de requête T-SQL

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 

ainsi de suite ...

Il y a environ 1000 lignes dans ce tableau. Je veux afficher des nœuds individuels dans des colonnes séparées. Nombre maximum de colonnes à afficher 5 (c'est-à-dire jusqu'à 5 niveaux de profondeur). Ainsi, la sortie regardera comme ci-dessous

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 

La seule façon que je peux penser est d'ouvrir un curseur, boucle à travers chaque ligne et effectuer une scission de chaîne, juste aller chercher les 5 premiers noeuds, puis insérer dans une température table.

Veuillez nous suggérer.

Merci

+0

SQL Server 2008 a hierarchyid (http://technet.microsoft.com/en-us/library/bb677173.aspx). Totalement recommandé Il supporte des méthodes utiles comme GetLevel et GetAncestor qui peuvent être utilisées ensemble pour résoudre ce problème. Accordé, ce serait tricher comme une réponse ici car il change le schéma de la table d'entrée :-) –

Répondre

0

Qu'est-ce que vous avez besoin est une fonction de répartition d'une valeur de table semblable à ce qui suit:

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 

Cette fonction repose sur l'existence d'une table Numbers qui contient une liste séquentielle des entiers. Maintenant, vous pouvez prendre vos données originales et faire quelque chose comme:

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] 
+0

Merci Thomas. Alors devrais-je créer une table Numbers temporaire? Combien de lignes doit contenir la table Numbers? – stackoverflowuser

+0

@stackoverflowuser - Il n'y a aucune raison que la table ne puisse pas être permanente. Il y a beaucoup d'utilisations pour une table de nombres et ceci est juste l'un d'entre eux. Si vous remarquez dans la fonction Split, il filtre sur la longueur de la chaîne, de sorte que la table de nombres doit être au moins aussi grande que la plus grande chaîne. Cependant, les rangées de 10K prendront peu de place et devraient être plus que suffisantes pour ce dont vous avez besoin. – Thomas

+0

Salut Thomas, je ne peux pas passer "Chemin" (colonne de la table d'entrée) comme entrée à dbo.udf_Split. Cela me donne une erreur de colonne invalide. D'où vient aussi la colonne "Element"? Merci. – stackoverflowuser