2017-04-21 3 views
1

ich SQL Server 2012 bin mit und ich habe folgendes Problem:gilt rekursiv LEFT JOIN

Ich habe das diese Tabelle (Kategorie):

IDCategory| CategoryDesc  | Father 
1   | R1    | 0 
2   | R1 - ST   | 1 
3   | R1 - CT   | 1 
4   | R1 - ST - SA  | 2 
5   | R1 - ST - CA 10 | 2 
6   | R1 - ST - CA 20 | 2 
7   | R1 - CT - CA  | 3 
8   | R1 - CT - SA  | 3 
9   | R2    | 0 
10  | R2 ST   | 9 
.   
.   
until R9   

und diese (CategoryDefinition):

IDCategory| First| Last 
1   | 0 | 300 
9   | 301 | 600 
.   
.   
.   

Und ich verwende die folgende Abfrage, weil ich weiß, es sind nur drei Ebenen:

SELECT 
cat3.IDCategory, 
cat.CategoryDesc AS title1, 
cat2.CategoryDesc AS title2, 
cat3.CategoryDesc AS title3, 
catdef.First, 
catdef.Last 
FROM Category as cat 
LEFT JOIN Category AS cat2 ON cat2.Father=cat.IDCategory 
LEFT JOIN Category AS cat3 ON cat3.Father=cat2.IDCategory 
INNER JOIN CategoryDefinition as catdef on cat.IDCategory = catdef.IDCategory 
WHERE cat3.IDCategory = 7 

Abfrageergebnis:

IDCategory| title1 | title2 |title3  |First|Last 
    7  | R1  | R1 - CT | R1 - CT - CA | 0 | 300 

Aber wie kann ich diese rekursiv zu machen? Für den Fall, dass in Zukunft neue Level erscheinen könnten (Ich muss also keinen neuen linken Join für jede neue Ebene hinzufügen, die erscheint).

Danke!

+0

Wollen Sie wirklich jede 'title' in seinem eigenen wollen Säule? Ein dynamischer Pivot einer rekursiven Cte scheint nur eine schlechte Idee zu sein. – SqlZim

+0

@SqlZim was du sagst ist, nur Titel3 zu zeigen? Anstatt alle 3 Titel anzuzeigen? – fedee13

+0

@SqlZim Ich (angeblich) brauche sie getrennt, weil die Verwendung muss jede Ebene auswählen. Erste Stufe 1 (R1, R2, R3 ....), nach Stufe 1 zeige ich die Optionen für Stufe 2 (ST oder CT), und entsprechend Stufe 2 zeige ich Stufe 3 (ST - SA, ST - CA 10, ST - CA 20 oder CT - CA, CT - SA). – fedee13

Antwort

0

ich kann zumindest helfen mit dem recusive CTE einer Adjazenzliste und eine materialisierte Pfad bauen:

Für diese Tabelle:

create table category (IDCategory int primary key,CategoryDesc varchar(32),Father int) 
insert into category values 
(1,'R1',0) 
,(2,'ST',1) 
,(3,'CT',1) 
,(4,'SA',3) 
,(5,'SA 10',2) 
,(6,'SA 20',2) 
,(7,'CA',2) 
,(8,'SA',2) 
,(9,'R2',0) 
,(10,'ST',9) 

eine rekursive CTE mit:

;with cte as (
-- anchor elements: where Father = 0 
    select 
     IDCategory 
    , categoryDesc 
    , Father 
    , parentName = convert(varchar(32),null) 
    , path = convert(varchar(128),categoryDesc) 
    from category 
    where Father = 0 
    -- recursion begins here 
    union all 
    select 
     c.IDCategory 
    , c.categoryDesc 
    , c.Father 
    , parentName = p.categoryDesc 
    , path = convert(varchar(128),p.path+' - '+c.categoryDesc) 
    from category c 
    inner join cte as p on c.Father= p.IDCategory 
) 
-- we select all the results 
select cte.* 
from cte 
order by idCategory 

Rückkehr:

+------------+--------------+--------+------------+-----------------+ 
| IDCategory | categoryDesc | Father | parentName |  path  | 
+------------+--------------+--------+------------+-----------------+ 
|   1 | R1   |  0 | NULL  | R1    | 
|   2 | ST   |  1 | R1   | R1 - ST   | 
|   3 | CT   |  1 | R1   | R1 - CT   | 
|   4 | SA   |  3 | CT   | R1 - CT - SA | 
|   5 | SA 10  |  2 | ST   | R1 - ST - SA 10 | 
|   6 | SA 20  |  2 | ST   | R1 - ST - SA 20 | 
|   7 | CA   |  2 | ST   | R1 - ST - CA | 
|   8 | SA   |  2 | ST   | R1 - ST - SA | 
|   9 | R2   |  0 | NULL  | R2    | 
|   10 | ST   |  9 | R2   | R2 - ST   | 
+------------+--------------+--------+------------+-----------------+ 

Hinzufügen der auf den Anker des rekursiven CTE verbinden:

;with cte as (
-- anchor elements: where Father = 0 
    select 
     c.IDCategory 
    , c.categoryDesc 
    , c.Father 
    , parentName = convert(varchar(32),null) 
    , path = convert(varchar(128),c.categoryDesc) 
    , cd.First 
    , cd.Last 
    from category c 
    inner join CategoryDefinition cd 
     on c.IdCategory=cd.IdCategory 
    where Father = 0 
    -- recursion begins here 
    union all 
    select 
     c.IDCategory 
    , c.categoryDesc 
    , c.Father 
    , parentName = p.categoryDesc 
    , path = convert(varchar(128),p.path+' - '+c.categoryDesc) 
    , p.First 
    , p.Last 
    from category c 
    inner join cte as p on c.Father= p.IDCategory 
) 
select cte.* 
from cte 
--where IdCategory = 7 
order by idCategory 

rextester Demo: http://rextester.com/POSVP81190

kehrt:

+------------+--------------+--------+------------+-----------------+-------+------+ 
| IDCategory | categoryDesc | Father | parentName |  path  | First | Last | 
+------------+--------------+--------+------------+-----------------+-------+------+ 
|   1 | R1   |  0 | NULL  | R1    |  0 | 300 | 
|   2 | ST   |  1 | R1   | R1 - ST   |  0 | 300 | 
|   3 | CT   |  1 | R1   | R1 - CT   |  0 | 300 | 
|   4 | SA   |  3 | CT   | R1 - CT - SA |  0 | 300 | 
|   5 | SA 10  |  2 | ST   | R1 - ST - SA 10 |  0 | 300 | 
|   6 | SA 20  |  2 | ST   | R1 - ST - SA 20 |  0 | 300 | 
|   7 | CA   |  2 | ST   | R1 - ST - CA |  0 | 300 | 
|   8 | SA   |  2 | ST   | R1 - ST - SA |  0 | 300 | 
|   9 | R2   |  0 | NULL  | R2    | 301 | 600 | 
|   10 | ST   |  9 | R2   | R2 - ST   | 301 | 600 | 
+------------+--------------+--------+------------+-----------------+-------+------+