usando recursivas jerárquicas hacer consultas como arbol sql postgresql tree hierarchical-data

recursivas - SQL Encuentra todos los descendientes directos en un árbol



como hacer un arbol en sql (2)

Encontré una consulta que funciona de la manera que quería.

SELECT * FROM ( SELECT id FROM t_tree WHERE name = '''' ) AS i, t_tree g WHERE ( ( i.id = g.id ) AND NOT EXISTS ( SELECT * FROM t_tree WHERE parentid = i.id ) ) OR ( ( i.id = g.parentid ) AND EXISTS ( SELECT * FROM t_tree WHERE parentid = i.id ) )

Tengo un árbol en mi base de datos que se almacena usando enlaces de id.

Una muestra de lo que tengo para los datos en la tabla es:

id | name | parent id ---+-------------+----------- 0 | root | NULL 1 | Node 1 | 0 2 | Node 2 | 0 3 | Node 1.1 | 1 4 | Node 1.1.1| 3 5 | Node 1.1.2| 3

Ahora me gustaría obtener una lista de todos los descendientes directos de un nodo determinado, pero si no existe ninguno, me gustaría que devuelva el nodo.

Quiero que el retorno para la consulta para hijos de id = 3 sea:

children -------- 4 5

Entonces la consulta para los hijos de id = 4 es:

children -------- 4

Puedo cambiar la forma en que estoy almacenando el árbol en un conjunto anidado, pero no veo cómo eso haría posible la consulta que deseo.


En el nuevo PostgreSQL 8.4 , puede hacerlo con un CTE :

WITH RECURSIVE q AS ( SELECT h, 1 AS level, ARRAY[id] AS breadcrumb FROM t_hierarchy h WHERE parent = 0 UNION ALL SELECT hi, q.level + 1 AS level, breadcrumb || id FROM q JOIN t_hierarchy hi ON hi.parent = (q.h).id ) SELECT REPEAT('' '', level) || (q.h).id, (q.h).parent, (q.h).value, level, breadcrumb::VARCHAR AS path FROM q ORDER BY breadcrumb

Vea este artículo en mi blog para más detalles:

En 8.3 o anterior, tendrás que escribir una función:

CREATE TYPE tp_hierarchy AS (node t_hierarchy, level INT); CREATE OR REPLACE FUNCTION fn_hierarchy_connect_by(INT, INT) RETURNS SETOF tp_hierarchy AS $$ SELECT CASE WHEN node = 1 THEN (t_hierarchy, $2)::tp_hierarchy ELSE fn_hierarchy_connect_by((q.t_hierarchy).id, $2 + 1) END FROM ( SELECT t_hierarchy, node FROM ( SELECT 1 AS node UNION ALL SELECT 2 ) nodes, t_hierarchy WHERE parent = $1 ORDER BY id, node ) q; $$ LANGUAGE ''sql'';

y seleccione de esta función:

SELECT * FROM fn_hierarchy_connect_by(4, 1)

El primer parámetro es el id la raíz, el segundo debe ser 1 .

Vea este artículo en mi blog para más detalles:

Actualizar:

Para mostrar solo los niños de primer nivel o el nodo si los niños no existen, emita esta consulta:

SELECT * FROM t_hierarchy WHERE parent = @start UNION ALL SELECT * FROM t_hierarchy WHERE id = @start AND NOT EXISTS ( SELECT NULL FROM t_hierarchy WHERE parent = @start )

Esto es más eficiente que un JOIN , ya que la segunda consulta tomará como máximo dos escaneos de índice: el primero para asegurarse de averiguar si existe un niño, el segundo para seleccionar la fila principal si no existen niños.