2011-01-12 10 views
3

Ich verwende eine Funktion Split (auf social.msdn.com gefunden), und wenn manuell in einem AbfragefensterSQL Split - einfügen in hierarchische Tabellenstruktur

SELECT * FROM dbo.Split('/ABC/DEF/GHI/JKL', '/') 

ich folgendes erhalten Ausführung

Id Name 
-- ---- 
1 
2 ABC 
3 DEF 
4 GHI 
5 JKL 

Dabei ist Id ist nur eine fortlaufende Nummer, die Position innerhalb der ursprünglichen Zeichenfolge angibt und Name ist der Name dieses Knotens. Noch keine hierarchische Information.

Jetzt ist der nächste Schritt, dies in eine hierarchische Datenstruktur in der DB zu setzen. Ich versuche, dies in einem gespeicherten Prozess zu tun und mit meinen SQL-Fähigkeiten, was sie sind, habe ich eine Wand getroffen. Hier ist, was ich würde wie haben: (. FEST, dass die ID-Spalte oben nicht auf die Id oder die ParentId Spalte hier verwendet ist)

Id ParentId Name FullName 
-- -------- ---- -------- 
1  NULL  ABC /ABC 
2  1  DEF /ABC/DEF 
3  2  GHI /ABC/DEF/GHI 
4  3  JKL /ABC/DEF/GHI/JKL 

ich das habe weit mit meinem SP (GetId mit param @FullName) - GetId sollte die ID zurückgeben, die diesem Knoten zugeordnet ist. Wenn der Knoten nicht existiert, sollte er erstellt werden und die ID aus dieser neuen Zeile sollte zurückgegeben werden. Mit anderen Worten, der Verbraucher dieses SP sollte sich nicht darum kümmern oder wissen, ob der Knoten existiert, bevor er aufgerufen wird:

Die Kategorietabelle (Adjazenzliste), in der diese Elemente schließlich durch eine Reihe von Einfügungen enden, hat die folgende Struktur.

CREATE TABLE Category (
    Id int IDENTITY(1,1) NOT NULL PRIMARY KEY, 
    ParentId int NULL, 
    Name nvarchar(255) NOT NULL, 
    FullName nvarchar(255) NOT NULL) 

Als Ergebnis, ich will keinen Wert für die Spalte von Id in der Kategorie Tabelle erzeugen und benötigen die entsprechende ParentId für jeden Knoten zu erhalten.

Nachdem die Pfade '/ ABC/DEF/GHI/JKL' und '/ ABC/DEF/XYZ/LMN/OPQ' verarbeitet wurden, und ich habe SELECT a * FROM Kategorie, würde ich erwarten, dass die folgenden sehen:

Id ParentId Name FullName 
-- -------- ---- -------- 
1  NULL  ABC /ABC 
2  1  DEF /ABC/DEF 
3  2  GHI /ABC/DEF/GHI 
4  3  JKL /ABC/DEF/GHI 
5  2  XYZ /ABC/DEF/XYZ 
6  5  LMN /ABC/DEF/XYZ/LMN 
7  6  OPQ /ABC/DEF/XYZ/LMN/OPQ 

Q: wäre es möglich, ausgehend von der äußersten Knoten rekursiv zurück in die SP zu nennen, bis der Knoten existiert oder wir waren an der Mutter? Etwas in der Art von:

GetId(@FullName) 
{ 
If Category exists with @FullName 
    return CatId 
Else // row doesn't exist for this node 
    Split @FullName, order by Id DESC so we get the leaf node first 
    Create Category row 
     @FullName, 
     @Name, 
     @ParentId = Id of next FullName (call GetId with FullName of next row from Split) 
} 
+0

Mit welcher Version von SQL Server arbeiten Sie? Wenn 2008 Sie [hierarchyid] (http://msdn.microsoft.com/en-us/magazine/cc794278.aspx) berücksichtigt haben? –

+0

Ich bin auf SQL Server 2008 –

+0

Die Art, wie Sie die Pfade bezeichnen, erinnerte mich ziemlich viel an das 'hierarchyid' Format. Ich habe es selbst nicht benutzt, weiß also nicht, ob es für deine Zwecke besser geeignet wäre als das Adjazenzlistenmodell ... –

Antwort

3

Sie können CTE verwenden, um dies zu erreichen, in Kombination mit RowNumbering

With TMP AS (
    SELECT Id, Data as Name, RN=ROW_NUMBER() over (Order by Id ASC) 
    FROM dbo.Split('/ABC/DEF/GHI/JKL', '/') 
    where Data > '' 
), TMP2 AS (
    SELECT TOP 1 RN, CONVERT(bigint, null) ParentId, Name, convert(nvarchar(max),'/' + Name) FullName 
    From TMP 
    Order by RN 
    union all 
    SELECT n.RN, t.RN, n.Name, t.FullName + '/' + n.Name 
    from TMP2 t 
    inner join TMP n on n.RN = t.RN+1) 
select * 
from tmp2 
order by RN 

Nun zum zweiten Teil, das fügt die gesamte Hierarchie, sondern beginnt mit ID = 1

IF (@count = 0) 
BEGIN 
    With TMP AS (
     SELECT Id, Data as Name, RN=ROW_NUMBER() over (Order by Id ASC) 
     FROM dbo.Split('/ABC/DEF/GHI/JKL', '/') 
     where Data > '' 
    ), TMP2 AS (
     SELECT TOP 1 RN, CONVERT(bigint, null) ParentId, Name, convert(nvarchar(max),'/' + Name) FullName 
     From TMP 
     Order by RN 
     union all 
     SELECT n.RN, t.RN, n.Name, t.FullName + '/' + n.Name 
     from TMP2 t 
     inner join TMP n on n.RN = t.RN+1) 
    insert Category(CatId, ParentId, Name, FullName) --<< list correct column names 
    select RN, ParentId, Name, FullName 
    from tmp2 
    order by RN 
END 
+0

Ich bin mir noch nicht sicher was du mit dem 2. Teil machen willst.Der endgültige (re) konstruierte FullName wird zweifellos der Eingabe @FullName entsprechen. Was also ist der Zweck der Aufteilung? – RichardTheKiwi

+0

@cyberwiki Ich möchte eine Reihe von Einfügungen machen, die die hierarchische Struktur in das Adjazenzlisten-DB-Schema erzeugen. Ich bin nicht sicher, wie die obige Lösung in ein Einsatz-Szenario passen würde. –

+0

@ Ed.S. Immer noch nicht 100% sicher. Sie möchten testen, ob der Name _full_ vorhanden ist, und wenn nicht der gesamte Baum eingefügt wird (Teile davon können bereits existieren, z. B. könnte/ABC an anderer Stelle existieren). Die IDs werden in eine Identitätsspalte eingefügt, sodass die ParentIDs angepasst werden müssen. – RichardTheKiwi