Между тем, существует способ однозначного выявления циклов без "наматывания" кругов по графу. Рассмотрим граф, показанный на рисунке ниже:
В базе данных он хранится в виде матрицы смежностей в таблице t:
CREATE TABLE t ( a INTEGER, b INTEGER )
Соответственно, исходные данные:
INSERT INTO t VALUES (1, 2); INSERT INTO t VALUES (2, 3); INSERT INTO t VALUES (3, 4); INSERT INTO t VALUES (3, 5); INSERT INTO t VALUES (3, 6); INSERT INTO t VALUES (2, 7); INSERT INTO t VALUES (6, 1);
Для поиска кольцевых ссылок напишем запрос:
with recursive tree as ( select distinct a as initial, a, b, -1 as prev from t union all select iif(tr.initial <> tt.a, tr.initial, -1) as initial, tt.a, tt.b, tr.a as prev from t tt JOIN tree tr ON tr.b = tt.a and tr.initial > 0 ) select * from tree where initial = -1
Запрос покажет все первые сегменты A - B (и предыдущие, т.е. сегменты непосредственно приведшие к циклу, PREV - A), всех возможных циклов в заданных данных. В нашем случае:
INITIAL A B PREV -1 1 2 6 -1 2 3 1 -1 2 7 1 -1 3 4 2 -1 3 5 2 -1 3 6 2 -1 6 1 3
При необходимости проверить не входит ли в кольцо конкретный узел, следует прописать его ИД в первом запросе рекурсивного CTE:
with recursive tree as ( select distinct a as initial, a, b, -1 as prev from t where a = _some_id_ union all select iif(tr.initial <> tt.a, tr.initial, -1) as initial, tt.a, tt.b, tr.a as prev from t tt JOIN tree tr ON tr.b = tt.a and tr.initial > 0 ) select * from tree where initial = -1