J'ai deux tables
ID Task
1 1
2 2
3 3
4 4
Col1 depend
2 3
2 4
3 1
4 2
ID
et Col1
sont liés à travers la contrainte FK. Je veux trouver toutes les références circulaires. Ici ID
et Col1
est juste pour combiner des lignes de 2 tables, par exemple:
Task 1 can start anytime.
Task 2 can start only after completion of 3, 4 etc
1 –
2 – 3, 4, 1, 2 -- for 2 there is circular dependency
3 – 1
4 – 2, 3, 4 -- also circular dependency
Cas 2:
Col1 depend
2 3
2 4
3 1
4 5
5 2
ID Task
1 1
2 2
3 3
4 4
5 5
1
2 – 3, 4, 1, 5, 2 -- circular reference
3 – 1
4 – 5, 2, 3, 4 -- circular reference
5 – 2, 3, 4, 5 -- circular reference
Les références circulaires peuvent être disponibles à tout niveau de récursivité. Comment trouver de telles références circulaires?
[.____] Nous avons essayé une requête récursive, mais nous sommes allés dans une boucle infinie. Comment écrire une requête récursive pour cela?
J'ai adapté l'exemple à http://www.postgresql.org/docs/8.4/static/queries-with.html à votre cas:
WITH RECURSIVE search_graph(id, depends, depth, path, cycle) AS (
SELECT g.Col1, g.depends, 1,
ARRAY[g.Col1],
false
FROM deps g
UNION ALL
SELECT g.Col1, g.depends, sg.depth + 1,
path || g.Col1,
g.Col1 = ANY(path)
FROM deps g, search_graph sg
WHERE g.Col1 = sg.depends AND NOT cycle
)
SELECT distinct id FROM search_graph where cycle = true;
résultats:
ID
4
2
pour le premier exemple,
ID
4
2
5
pour la seconde
Vous pouvez trouver le FIDDLE SQL AT http://sqlfiddle.com/#!15/87A96/2
Construire également sur le exemple dans le manuel :
WITH RECURSIVE graph AS (
SELECT col1 AS id
, ARRAY[depend, col1] AS path
, (depend = col1) AS cycle -- first step could be circular
FROM dep
UNION ALL
SELECT d.col1, d.depend || path, d.depend = ANY(path)
FROM graph g
JOIN dep d ON d.col1 = g.path[1]
WHERE NOT g.cycle
)
SELECT DISTINCT id
FROM graph
WHERE cycle;
Résultat
id
2
4
5
Ceci est un peu plus simple et plus rapide:
Celui-ci prepends
le chemin avec le nouvel article respectif, afin que nous puissions utiliser path[1]
Au lieu d'une colonne supplémentaire. À ma connaissance, aussi vite que Ajout .
[.____] L'accès au premier élément d'un tableau doit être presque aussi bon marché qu'une colonne supplémentaire - qui rendrait la rangée plus large. Testez et comparez si la performance est importante:
WITH RECURSIVE graph AS (
SELECT col1 AS id, depend AS col1 -- simplify join condition
, ARRAY[col1, depend] AS path
, (col1 = depend) AS cycle -- simplify if short-circuit impossible
FROM dep
UNION ALL
SELECT d.col1, d.depend
, path || d.depend, d.depend = ANY(path)
FROM graph g
JOIN dep d USING (col1)
WHERE NOT g.cycle
)
SELECT DISTINCT id
FROM graph
WHERE cycle;