2016-06-01 2 views
3

Если у меня есть очень простая таблица называется treeДинамическая таблица, созданная с КТР (родитель/ребенок)

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

И несколько строк данных

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'); 

Я могу легко запустить КТР на нем, и производят выход дает мне путь, как этот

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; 

который дает выход

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 

Что я задаюсь, можно ли как-то спроецировать этот вывод в другой таблице, динамически создавать столбцы в зависимости от уровня (ровном1, level2, LEVEL3 и т.д.), что дает мне что-то подобное в ответ

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 

Любая помощь будет оценена по достоинству.

ответ

1

PostgreSQL требует, чтобы всегда определять тип вывода, поэтому вы не можете динамически создавать столбцы levelX. Тем не менее, вы можете сделать следующее:

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 

В приведенном выше примере, столбец row_number происходит в соответствии id, но, вероятно, что бы не случилось с реальными данными.

2

Если вы знаете максимальную глубину своего дерева, я бы сохранил ваш подход и упростил его с помощью конкатенации массива для получения желаемого результата. Так что для дерева 5 уровня, который будет выглядеть следующим образом:

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: извиняюсь за не комментируя ответ Зигги, который очень близко, но не хватает репутации сделать это. Я не понимаю, зачем вам нужна функция окон?

+0

На самом деле я понятия не имею, какова будет максимальная глубина. Начав думать, что мне может понадобиться создать таблицу для хранения моего вывода CTE, затем используйте функцию для создания + заполнения таблицы (я предполагаю, что реальный ответ заключается в том, что это невозможно в SQL). – mortenoh

+0

Использование функции PL/pgSQL в конечном итоге будет способом PostgreSQL. Но вам действительно нужны динамические столбцы? Если этот вывод довольно сложно создать, его также сложно использовать, если только вы не используете только инструкции SELECT *. – thewild

Смежные вопросы