J'ai cet exemple de travail CTE.
Je peux sélectionner tous les grands-parents et tous les enfants.
Mais comment puis-je sélectionner tous les grands-parents et tous les enfants dans une seule déclaration?
Dans cet exemple, je veux grand-père, père, fils comme sortie si je donne "Père" comme entrée.
J'utilise PostgreSQL. Mais je pense que cette question devrait être SQL standard.
Veuillez me corriger si j'utilise la syntaxe spécifique à PostgreSQL.
DROP table if exists tree;
CREATE TABLE tree (
id SERIAL PRIMARY KEY,
name character varying(64) NOT NULL,
parent_id integer REFERENCES tree NULL
);
insert into tree values (1, 'Grandfather', NULL);
insert into tree values (2, 'Father', 1);
insert into tree values (3, 'Son', 2);
-- -------------------------------------
-- Getting all children works
WITH RECURSIVE rec (id) as
(
SELECT tree.id, tree.name from tree where name='Father'
UNION ALL
SELECT tree.id, tree.name from rec, tree where tree.parent_id = rec.id
)
SELECT *
FROM rec;
-- Result:
-- id | name
-- ----+--------
-- 2 | Father
-- 3 | Son
-- -------------------------------------
-- Getting all parents works
WITH RECURSIVE rec (id) as
(
SELECT tree.id, tree.name, tree.parent_id from tree where name='Father'
UNION ALL
SELECT tree.id, tree.name, tree.parent_id from rec, tree where tree.id = rec.parent_id
)
SELECT id, name
FROM rec;
-- Result
-- id | name
-- ----+-------------
-- 2 | Father
-- 1 | Grandfather
Ci-dessus est un exemple de travail simplifié. L'arbre peut atteindre 100 niveaux de profondeur. Il peut y avoir plusieurs niveaux d'ancêtres au-dessus de "Père" et plusieurs niveaux de descendants en dessous. Je veux tous les ancêtres et tous les descendants.
Si vous voulez tous les ancêtres et tous les descendants, vous pouvez combiner les deux requêtes en une seule. Utilisez les deux CTE puis un simple UNION
:
WITH RECURSIVE
-- descendants
rec_d (id, name) AS
(
SELECT tree.id, tree.name FROM tree WHERE name = 'Father'
UNION ALL
SELECT tree.id, tree.name FROM rec_d, tree where tree.parent_id = rec_d.id
),
-- ancestors
rec_a (id, name, parent_id) AS
(
SELECT tree.id, tree.name, tree.parent_id FROM tree WHERE name = 'Father'
UNION ALL
SELECT tree.id, tree.name, tree.parent_id FROM rec_a, tree WHERE tree.id = rec_a.parent_id
)
SELECT id, name FROM rec_a
UNION
SELECT id, name FROM rec_d ;
Si nous n'avons pas eu d'erreurs ci-dessus, nous pouvons les améliorer:
UNION
final en UNION ALL
en plaçant le ou les nœuds de départ dans un seul des CTE.JOIN .. ON
au lieu des jointures implicites.La requête devient:
WITH RECURSIVE
-- starting node(s)
starting (id, name, parent_id) AS
(
SELECT t.id, t.name, t.parent_id
FROM tree AS t
WHERE t.name = 'Father' -- this can be arbitrary
),
descendants (id, name, parent_id) AS
(
SELECT s.id, s.name, s.parent_id
FROM starting AS s
UNION ALL
SELECT t.id, t.name, t.parent_id
FROM tree AS t JOIN descendants AS d ON t.parent_id = d.id
),
ancestors (id, name, parent_id) AS
(
SELECT t.id, t.name, t.parent_id
FROM tree AS t
WHERE t.id IN (SELECT parent_id FROM starting)
UNION ALL
SELECT t.id, t.name, t.parent_id
FROM tree AS t JOIN ancestors AS a ON t.id = a.parent_id
)
TABLE ancestors
UNION ALL
TABLE descendants ;