Рассмотрим следующий простой DAG:
1->2->3->4
И таблица, #bar, описывающая это (я использую SQL Server 2005):
parent_id child_id
1 2
2 3
3 4
//... other edges, not connected to the subgraph above
Теперь представьте, что у меня есть некоторые другие произвольные критерии, которые выбирают первое и последнее ребра, то есть 1-> 2 и 3-> 4. Я хочу использовать их, чтобы найти остальную часть моего графика.
Я могу написать рекурсивный CTE следующим образом (я использую терминологию из MSDN ):
with foo(parent_id,child_id) as (
// anchor member that happens to select first and last edges:
select parent_id,child_id from #bar where parent_id in (1,3)
union all
// recursive member:
select #bar.* from #bar
join foo on #bar.parent_id = foo.child_id
)
select parent_id,child_id from foo
Однако это приводит к тому, что ребро 3-> 4 выбирается дважды:
parent_id child_id
1 2
3 4
2 3
3 4 // 2nd appearance!
Как я могу предотвратить повторение запроса в подграфах, которые уже были описаны? Я мог бы добиться этого, если бы в моей части запроса «рекурсивный элемент» я мог ссылаться на все данные, которые были получены рекурсивным CTE до сих пор (и предоставлять предикат, указывающий на рекурсивный член, исключая узлы уже побывал). Однако я думаю, что могу получить доступ к данным, которые были возвращены последней итерацией только рекурсивного члена.
Это не будет хорошо масштабироваться, когда таких повторений много. Есть ли способ предотвратить эту ненужную дополнительную рекурсию?
Обратите внимание, что я мог бы использовать «выбрать отличное» в последней строке моего утверждения, чтобы достичь желаемых результатов, но это, кажется, применимо после , когда вся (повторная) рекурсия выполнена, поэтому я не не думаю, что это идеальное решение.
Редактировать - hainstech предлагает остановить рекурсию, добавив предикат, чтобы исключить рекурсивные нисходящие пути, которые были явно в начальном наборе, т.е. только рекурсия where foo.child_id not in (1,3)
. Это работает для случая выше только потому, что это просто - все повторяющиеся разделы начинаются внутри якорного набора узлов. Это не решает общий случай, когда они не могут быть. например, рассмотрите добавление ребер 1-> 4 и 4-> 5 к вышеуказанному набору. Край 4-> 5 будет захвачен дважды, даже с предложенным предикатом. (