2010-07-22 21 views
12

Necesito ayuda con una consulta recursiva. Suponiendo que la siguiente tabla:PostgreSQL recursivo con

CREATE TEMPORARY TABLE tree (
    id  integer PRIMARY KEY, 
    parent_id integer NOT NULL, 
    name  varchar(50) 
);  

INSERT INTO tree (id, parent_id, name) VALUES (3, 0, 'Peter'), (2,0, 'Thomas'), (5,2, 'David'), (1, 0, 'Rob'), (8, 0, 'Brian'); 

puedo recuperar una lista de todas las personas y sus niños con la siguiente consulta:

WITH RECURSIVE recursetree(id, parent_id) AS (
    SELECT id, parent_id FROM tree WHERE parent_id = 0 
    UNION 
    SELECT t.id, t.parent_id 
    FROM tree t 
    JOIN recursetree rt ON rt.id = t.parent_id 
) 
SELECT * FROM recursetree; 

¿Cómo les puedo obtener una lista en orden, y también ordenar los primeros elementos de nivel ¿por nombre? Por ejemplo, la salida deseada sería:

id, parent_id, name  
8, 0, "Brian" 
3, 0, "Peter" 
1, 0; "Rob" 
2, 0, "Thomas" 
5, 2, " David" 

Gracias,

** EDIT. Tenga en cuenta que la adición de un ORDER BY no funcionará: **

WITH RECURSIVE recursetree(id, parent_id, path, name) AS (
    SELECT 
     id, 
     parent_id, 
     array[id] AS path, 
     name 
    FROM tree WHERE parent_id = 0 
    UNION ALL 
    SELECT t.id, t.parent_id, rt.path || t.id, t.name 
    FROM tree t 
    JOIN recursetree rt ON rt.id = t.parent_id 
) 
SELECT * FROM recursetree ORDER BY path; 

Lo anterior conservará la relación entre padres e hijos (niños siguen a sus padres), pero la aplicación de cualquier otra cláusula ORDER BY (es decir: nombre - como algunos han sugerido) hará que el resultado pierda sus relaciones entre padres e hijos.

+1

no es un orderBy sencilla haciendo el truco? –

+0

Una ORDEN POR no colocar a los niños debajo de sus padres, solo ordena todo por su nombre. – robdog

Respuesta

7

Ver también este artículo (traducido) acerca de CTE en PostgreSQL: wiki.phpfreakz.nl

Editar: Prueba con esto, el uso de una matriz:

WITH RECURSIVE recursetree(id, parent_ids, firstname) AS (
    SELECT id, NULL::int[] || parent_id, name FROM tree WHERE parent_id = 0 
    UNION ALL 
    SELECT 
    t.id, 
    rt.parent_ids || t.parent_id, 
    name 
    FROM tree t 
    JOIN recursetree rt ON rt.id = t.parent_id 
) 
SELECT * FROM recursetree ORDER BY parent_ids; 
+0

Gracias por el enlace. Sin embargo, la clave del problema sigue siendo: debo ordenar por ruta para conservar el orden, pero debo ordenar los artículos de nivel superior por un campo (en este caso, el nombre). – robdog

+0

Simplemente use una matriz en el CTE, un niño siempre tendrá más elementos en la matriz como sus padres, una orden ASCending hará el truco. –

+0

probablemente "ORDER BY parent_ids, firstname" para ordenar los elementos de nivel superior por nombre también (que todos tendrán {0} como sus parent_ids) – araqnid