2016-06-01 10 views
3

Wenn ich eine sehr einfache Tabelle treeDynamische Tabelle von CTE erstellt (Eltern/Kind)

create table if not exists tree (id int primary key, parent int, name text); 

genannt haben und ein paar Zeilen von Daten

insert into tree values (1, null, 'A'); 
insert into tree values (2, 1, 'B'); 
insert into tree values (3, 1, 'C'); 
insert into tree values (4, 2, 'D'); 
insert into tree values (5, 2, 'E'); 
insert into tree values (6, 3, 'F'); 
insert into tree values (7, 3, 'G'); 

ich leicht CTEs darauf laufen kann, und produziert gibt einen Ausgang mir Pfad so

with recursive R(id, level, path, name) as (
    select id,1,name,name from tree where parent is null 
    union select tree.id, level + 1, path || '.' || tree.name, tree.name from tree join R on R.id=tree.parent 
) select level,path,name from R; 

, die den Ausgang gibt

level | path | name 
-------+-------+------ 
    1 | A  | A 
    2 | A.B | B 
    2 | A.C | C 
    3 | A.B.D | D 
    3 | A.B.E | E 
    3 | A.C.F | F 
    3 | A.C.G | G 

Was ich frage mich, ist es möglich, diese Ausgabe in einer anderen Tabelle irgendwie zu projizieren, dynamisch Spalten basierend auf Ebene (Ebene 1, Level2, Level3 usw.) zu schaffen, mir so im Gegenzug etwas geben

id | level1 | level2 | level3 
---+--------+--------+------- 
1 | A  |  | 
2 | A  | B  | 
3 | A  | C  | 
4 | A  | B  | D 
5 | A  | B  | E 
6 | A  | C  | F 
7 | A  | C  | G 

Jede Hilfe wäre willkommen.

Antwort

1

PostgreSQL muss immer den Typ der Ausgabe definieren, so dass die Spalten levelX nicht dynamisch erzeugt werden können. Allerdings können Sie folgendes tun:

with recursive 
    R(id, path) as (
    select id,ARRAY[name::text] from tree where parent is null 
    union 
    select tree.id, path || tree.name::text from tree join R on R.id=tree.parent 
    ) 
select row_number() over (order by cardinality(path), path), id, 
     path[1] as level1, path[2] as level2, path[3] as level3 
from R 
order by 1 

In dem obigen Beispiel wird die Spalte row_number geschieht id, paßt aber wahrscheinlich, dass nicht mit realen Daten geschehen.

2

Wenn Sie die maximale Tiefe Ihres Baumes kennen, würde ich Ihren Ansatz beibehalten und vereinfachen, Array-Verkettung verwenden, um die gewünschte Ausgabe zu produzieren. Also für einen 5-Ebene Baum, die wie folgt aussehen:

WITH RECURSIVE R(id, path) AS (
    SELECT id, ARRAY[name::text] FROM tree WHERE parent IS NULL 
    UNION SELECT tree.id, path || tree.name FROM tree JOIN R ON R.id=tree.parent 
) 
SELECT id, 
    path[1] AS l1, 
    path[2] AS l2, 
    path[3] AS l3, 
    path[4] AS l4, 
    path[5] AS l5 
FROM R; 

PS: Sorry für die nicht kommentiert Ziggys Antwort, die ganz in der Nähe ist, aber ich habe nicht genug Ruf, dies zu tun. Ich sehe nicht, warum Sie hier eine Fensterfunktion benötigen würden?

+0

Eigentlich habe ich keine Ahnung was die maximale Tiefe wäre. Beginnen zu denken, dass ich eine Tabelle erstellen muss, um meine CTE-Ausgabe zu behalten, dann benutze eine Funktion, um + die Tabelle zu füllen (ich denke, die wirkliche Antwort ist, dass dies in SQL nicht möglich ist). – mortenoh

+0

Mit einer PL/pgSQL-Funktion wäre definitiv die PostgreSQL-Methode zu gehen. Aber brauchen Sie wirklich dynamische Spalten? Wenn diese Ausgabe ziemlich schwierig zu erstellen ist, ist sie auch schwierig zu verwenden, es sei denn, Sie verwenden nur SELECT-Anweisungen. – thewild

Verwandte Themen