1

Ich habe Tabelle wie folgt Angenommen:hierarchische Struktur, neue Spalten, Denormalisierung

id parent_id name 
11  NULL  Company 
33  11  Department 1 
44  33  Department 2 

Ich möchte es in verwandeln:

id parent_id name   Level1  Level2  Level3 
11  NULL  Company  NULL  NULL   NULL 
22  11   Company Department 1 NULL   NULL 
33  22   Company Department 1 Department 2 NULL 

ich in der Lage bin einen CTE zu schaffen und kommen mit Levels Spalte zeigt einen Wert in der Hierarchie an, aber ich weiß nicht, wie ich neue Spalten für Abteilungen wie dargestellt anlegen soll.

with myCTE as (
     select c.id, c."name", c.parent_id, 1 as Level 
     from table1 c 
     where c.parent_id IS NULL 

     UNION ALL 

     Select c1.id, c1."name", c1.parent_id, Level +1 
     from table1 c1 
     inner join myCTE on c1.parent_id = myCTE.id 
     where c1.parent_id IS NOT NULL 
    ) 

select * from myCTE 

zeigt:

  id  parent_id name   level 
    1  11  NULL  Company  1 
    2  22  11   Department 2 2 
    3  33  22   Department 3 3 
+0

Ist die maximale Tiefe begrenzt? Wie viele Stufen erwarten Sie? – Shnugo

+0

Ich würde erwarten, dass es ideal dynamisch ist, aber ich habe so weit bis zum 9. Level – user3015289

Antwort

2

Ein (fast) vollständig generischer Ansatz:

DECLARE @tbl TABLE(id INT,parent_id INT,name VARCHAR(100)); 
INSERT INTO @tbl VALUES 
(11,NULL,'Company') 
,(33,11,'Department 1') 
,(44,33,'Department 2a') 
,(55,33,'Department 2b') 
,(66,44,'SubDep 2a'); 

--Die rekursiven CTE wird ein XML-Fragment auf einem Zeile-für-Zeile Ebene --Die SELECT wird XML verwenden Methode .nodes() bauen und zu ROW_NUMBER Spaltennamen für PIVOT

WITH recCTE AS 
(
    SELECT id, parent_id,name,(SELECT name AS [*] FOR XML PATH('')) AS NameConcat 
    FROM @tbl WHERE parent_id IS NULL 

    UNION ALL 

    SELECT t.id,t.parent_id,t.name,recCTE.NameConcat + '</lvl><lvl>' + (SELECT t.name AS [*] FOR XML PATH('')) 
    FROM @tbl AS t 
    INNER JOIN recCTE ON recCTE.id=t.parent_id 
) 
SELECT p.* 
FROM 
(
    SELECT id 
      ,parent_id 
      ,name 
      ,'Level' + REPLACE(STR(ROW_NUMBER() OVER(PARTITION BY id ORDER BY (SELECT NULL)),2),' ','0') AS HierarchyRank 
      ,lvl.value(N'(./text())[1]','nvarchar(max)') AS HierarchyName 
    FROM recCTE 
    CROSS APPLY (SELECT CAST('<lvl>' + NameConcat + '</lvl>' AS XML) AS PreLevels) AS Casted 
    CROSS APPLY Casted.PreLevels.nodes(N'/lvl') AS A(lvl) 
) AS tbl 
PIVOT 
(
    MAX(HierarchyName) FOR HierarchyRank IN(Level01,Level02,Level03,Level04,Level05,Level06,Level07,Level08,Level09) 
) AS p; 
zu erzeugen

das Ergebnis

+----+-----------+----------------+---------+----------------+---------------+-----------+---------+ 
| id | parent_id | name   | Level01 | Level02  | Level03  | Level04 | Level05 | 
+----+-----------+----------------+---------+----------------+---------------+-----------+---------+ 
| 11 | NULL  | Company  | Company | NULL   | NULL   | NULL  | NULL | 
+----+-----------+----------------+---------+----------------+---------------+-----------+---------+ 
| 33 | 11  | Department 1 | Company | Department 1 | NULL   | NULL  | NULL | 
+----+-----------+----------------+---------+----------------+---------------+-----------+---------+ 
| 44 | 33  | Department 2a | Company | Department 1 | Department 2a | NULL  | NULL | 
+----+-----------+----------------+---------+----------------+---------------+-----------+---------+ 
| 55 | 33  | Department 2b | Company | Department 1 | Department 2b | NULL  | NULL | 
+----+-----------+----------------+---------+----------------+---------------+-----------+---------+ 
| 66 | 44  | SubDep 2a  | Company | Department 1 | Department 2a | SubDep 2a | NULL | 
+----+-----------+----------------+---------+----------------+---------------+-----------+---------+ 

Wenn Sie mehr Ebenen müssen, war die einzige Notwendigkeit mehr Spaltennamen in diehinzufügenTeil ...

+0

Schöne Lösung. –

0

Sie die Zeilen für jede Ebene berechnen kann, und vereinigen sie:

with MyCTE as (

select id, parent_id, name, null as level1, null as level2, null as level3 
from table1 as root 
where root.parent_id is null 

union 

select level1.id, level1.parent_id, root.name, level1.name as level1, null as level2, null as level3 
from table1 as level1 
    inner join table1 as root on root.id = level1.parent_id 
where root.parent_id is null 

union 

select level2.id, level2.parent_id, root.name, level1.name as level1, level2.name as level2, null as level3 
from table1 as level2 
    inner join table1 as level1 on level1.id = level2.parent_id 
    inner join table1 as root on root.id = level1.parent_id 
where root.parent_id is null 

union 

select level3.id, level3.parent_id, root.name, level1.name as level1, level2.name as level2, level3.name as level3 
from table1 as level3 
    inner join table1 as level2 on level2.id = level3.parent_id 
    inner join table1 as level1 on level1.id = level2.parent_id 
    inner join table1 as root on root.id = level1.parent_id 
where root.parent_id is null 

) 
select * from MyCTE 

Wenn Sie mehr Ebenen benötigen, müssen Sie mehr wählt hinzufügen mit zusätzliche Verbindungen

Verwandte Themen