2013-10-24 2 views
1

Все рекурсивные примеры CTE, которые я могу найти, используют по существу тот же сценарий. Все они проходят вверх или вниз по орг-диаграмме. Мой CTE отлично подходит для отношений между родителями и детьми, которые являются индивидуальными, например, когда у одного сотрудника есть один менеджер, но у меня есть таблица, где у ребенка может быть несколько родителей. То, что я хочу, - это разборчивый список родительских идентификаторов, исходящих от одного ребенка.Рекурсивный CTE T-SQL с несколькими родительскими элементами

Если вас интересует специфика, я рекурсирую через предшественников конкретной задачи в файле MS Project. Я хочу начать с определенной вехи и проследить весь путь до вершины файла, чтобы найти любых предшественников, которые могут повлиять на веху. Как вы знаете, задача может иметь несколько предшественников.

Мои отношения выглядеть следующим образом:

tblTasks

child parent 
3  1 
16  1 
25  1 
25  3 
25  16 
26  1 
26  3 
27  25 
27  26 

Вот мой КТР:

;WITH ProjectTrace(Task) 
AS 
(
    -- Anchor member definition (This is task 27) 
    SELECT t.parent AS Task 
    FROM #tblTasks t 
    WHERE t.child = 27 

    UNION ALL 

    -- Recursive member definition (This is everything that hooks into 27 via predecessors) 
    SELECT t.parent AS Task 
    FROM #tblTasks t 
    INNER JOIN ProjectTrace trace 
     ON t.child = trace.Task 
) 
SELECT * FROM ProjectTrace ORDER BY Task 

Я хочу поставить задачу # 27 на запрос и получить только 1,3,16,25,26 в моих результатах. Однако, из-за способа рекурсия работает, мой ResultSet выглядит следующим образом:

Task 
1 
1 
1 
1 
1 
3 
3 
16 
25 
26 

Если посмотреть на отношения, я думаю, что имеет смысл. Я всегда могу изменить выделение конца выделенного элемента, но когда я получаю действительно глубокий вклад в проект, скажем, номер задачи 500, он возвращает миллионы записей.

Что я могу делать неправильно?

+1

Отсутствует 'DISTINCT' при последнем выборе? – Dan

+0

Нет ничего плохого в этом ... в чем проблема? Добавьте отчетливый, и вы gtg – Hogan

+0

Как я уже говорил в моем оригинальном посте: «Я всегда могу изменить выделение конца выделенного отдельного элемента, но когда я получаю действительно глубокий проект, скажем, номер задачи 500, он возвращает миллионы записей ». –

ответ

0

Я думаю, distinct - хороший способ сделать это. Вы также можете проверить итерационное решение вставки:

declare @Temp table(Task int primary key) 

insert into @Temp 
select distinct parent from Table1 where child = 27 

while 1 = 1 
begin 
    insert into @Temp 
    select distinct T.parent 
    from Table1 as T 
    where 
     exists (select * from @Temp as TT where TT.Task = T.child) and 
     not exists (select * from @Temp as TT where TT.Task = T.parent) 

    if @@rowcount = 0 break 
end 

select * from @Temp 

не знает, будет ли это быстрее, проверить это самостоятельно.

+0

Спасибо, Роман! Это идеально, и он работает WAY быстрее, чем CTE. Было бы очень приятно, если бы вы объяснили, что он делает. –

+0

@KevinSlane в принципе не просто вставляет в родительский элемент resultet данного дочернего элемента, а затем запускает бесконечный цикл, где проверяется, есть ли записи, в которых дочерний элемент в id и родительском элементе '@ Temp', а затем вставлять, если есть такой записей. –

+0

Хорошо, спасибо! Это действительно привело меня в пресловутый горб. Отлично работает для нас! –

0

Я не думаю, что есть более эффективный вариант, чем DISTINCT.

Вы не можете использовать LEFT JOIN, чтобы ограничить, где трассировка. Задайте IS NULL, вы не можете GROUP BY. Думаю, DISTINCT - это путь.

+0

Это несчастливо. Если это так, я боюсь, что решение CTE не будет работать для меня. Я не уверен, есть ли лучший, но я не могу опубликовать отчет, который занимает несколько минут. Ну, я ** МОЖЕТ **, но я не буду так много друзей. :) –

Смежные вопросы