Вы можете сделать это с помощью хранимых процедур (см. Листинги 7 и 7a):
http://www.artfulsoftware.com/mysqlbook/sampler/mysqled1ch20.html
Вам просто нужно выяснить запрос для шага рекурсии - взятьуже найденные строки и поиск еще нескольких строк.
Если у вас есть база данных, которая поддерживает рекурсивные общие табличные выражения SQL-99 (например, PostgreSQL или Firebird, подсказка подсказки), вы можете использовать тот же подход, что и вышессылка, но с использованием rCTE в качестве основы, поэтому избегая необходимости писать хранимую процедуру.
РЕДАКТИРОВАТЬ: я попытался сделать это с rCTE в PostgreSQL 8.4, и хотя я могу найти строки,я не могу найти способ обозначить их глубиной, на которой они были найдены.Во-первых, я создаю представление для объединения таблиц:
create view t12 (tbl, id, vala, valb) as (
(select 't1', id, vala, valb from t1)
union
(select 't2', id, vala, valb from t2)
)
Затем выполните этот запрос:
with recursive descendants (tbl, id, vala, valb) as (
(select *
from t12
where tbl = 't1' and id = 1) -- the query that identifies the seed rows, here just t1/1
union
(select c.*
from descendants p, t12 c
where (p.vala = c.vala or p.valb = c.valb)) -- the recursive term
)
select * from descendants;
Вы можете себе представить, что захват глубины будет таким же простым, как добавление столбца глубины кrCTE, равный нулю в начальном запросе, затем каким-то образом увеличивающийся на рекурсивном шаге.Тем не менее, я не смог найти никакого способа сделать это, учитывая, что вы не можете писать подзапросы к rCTE на рекурсивном шаге (так что ничего подобного select max(depth) + 1 from descendants
в списке столбцов), и вы не можете использовать агрегатную функциюв списке столбцов (поэтому max(p.depth) + 1
в списке столбцов в сочетании с group by c.*
для выбора).
Вам также необходимо добавить ограничение в запрос, чтобы исключить уже выбранные строки;вам не нужно делать это в базовой версии из-за отличительного эффекта объединения, но если вы добавите столбец подсчета, то строка может быть включена в результаты более одного раза с разным количеством, и выполучить картезианский взрыв.Но вы не можете легко предотвратить это, потому что у вас не может быть подзапросов к rCTE, что означает, что вы не можете сказать ничего подобного and not exists (select * from descendants d where d.tbl = c.tbl and d.id = c.id)
!
Я знаю, что все эти вещи о рекурсивных запросах бесполезныЯ использую это, но я нахожу это захватывающим, поэтому, пожалуйста, извините.