tutoriales query generar ejemplos consultas consulta sql sql-server database recursion

query - ¿Cómo creo una consulta recursiva en MSSQL 2005?



sql count group by (4)

A menos que me falta algo, la recursión no es necesaria ...

SELECT d.NAME FROM Customers As d INNER JOIN Customers As p ON p.CustomerID = d.ParentID WHERE p.Name = ''James''

Digamos que tengo la siguiente tabla:

CustomerID ParentID Name ========== ======== ==== 1 null John 2 1 James 3 2 Jenna 4 3 Jennifer 5 3 Peter 6 5 Alice 7 5 Steve 8 1 Larry

Quiero recuperar en una consulta a todos los descendientes de James (Jenna, Jennifer, Peter, Alice, Steve). Gracias, Pablo.


En SQL Server 2005 puede usar CTE (Common Table Expressions) :

with Hierachy(CustomerID, ParentID, Name, Level) as ( select CustomerID, ParentID, Name, 0 as Level from Customers c where c.CustomerID = 2 -- insert parameter here union all select c.CustomerID, c.ParentID, c.Name, ch.Level + 1 from Customers c inner join Hierachy ch on c.ParentId = ch.CustomerID ) select CustomerID, ParentID, Name from Hierachy where Level > 0


No puede hacer recursiones en SQL sin procedimientos almacenados. La forma de resolver esto es usar conjuntos anidados, básicamente modelan un árbol en SQL como un conjunto.

Tenga en cuenta que esto requerirá un cambio en el modelo de datos actual o posiblemente averiguar cómo crear una vista en el modelo original.

Ejemplo de Postgresql (usando muy pocas extensiones postgresql, solo SERIAL y ON COMMIT DROP, la mayoría de RDBMS tendrán una funcionalidad similar):

Preparar:

CREATE TABLE objects( id SERIAL PRIMARY KEY, name TEXT, lft INT, rgt INT ); INSERT INTO objects(name, lft, rgt) VALUES(''The root of the tree'', 1, 2);

Agregar un niño:

START TRANSACTION; -- postgresql doesn''t support variables so we create a temporary table that -- gets deleted after the transaction has finished. CREATE TEMP TABLE left_tmp( lft INT ) ON COMMIT DROP; -- not standard sql -- store the left of the parent for later use INSERT INTO left_tmp (lft) VALUES((SELECT lft FROM objects WHERE name = ''The parent of the newly inserted node'')); -- move all the children already in the set to the right -- to make room for the new child UPDATE objects SET rgt = rgt + 2 WHERE rgt > (SELECT lft FROM left_tmp LIMIT 1); UPDATE objects SET lft = lft + 2 WHERE lft > (SELECT lft FROM left_tmp LIMIT 1); -- insert the new child INSERT INTO objects(name, lft, rgt) VALUES( ''The name of the newly inserted node'', (SELECT lft + 1 FROM left_tmp LIMIT 1), (SELECT lft + 2 FROM left_tmp LIMIT 1) ); COMMIT;

Muestre un rastro de abajo hacia arriba:

SELECT parent.id, parent.lft FROM objects AS current_node INNER JOIN objects AS parent ON current_node.lft BETWEEN parent.lft AND parent.rgt WHERE current_node.name = ''The name of the deepest child'' ORDER BY parent.lft;

Mostrar el árbol completo:

SELECT REPEAT('' '', CAST((COUNT(parent.id) - 1) AS INT)) || ''- '' || current_node.name AS indented_name FROM objects current_node INNER JOIN objects parent ON current_node.lft BETWEEN parent.lft AND parent.rgt GROUP BY current_node.name, current_node.lft ORDER BY current_node.lft;

Seleccione todo desde un cierto elemento del árbol:

SELECT current_node.name AS node_name FROM objects current_node INNER JOIN objects parent ON current_node.lft BETWEEN parent.lft AND parent.rgt AND parent.name = ''child'' GROUP BY current_node.name, current_node.lft ORDER BY current_node.lft;


Para abajo, usa la respuesta de mathieu con una pequeña modificación:

with Hierachy(CustomerID, ParentID, Name, Level) as ( select CustomerID, ParentID, Name, 0 as Level from Customers c where c.CustomerID = 2 -- insert parameter here union all select c.CustomerID, c.ParentID, c.Name, ch.Level + 1 from Customers c inner join Hierachy ch -- EDITED HERE -- on ch.ParentId = c.CustomerID ----------------- ) select CustomerID, ParentID, Name from Hierachy where Level > 0