2015-10-09 2 views
2

У меня есть 2 таблицы: Document и DocumentLink. DocumentLink имеет 2 поля: MainDocID и LinkedDocID, которые заполнены значением DocID из таблицы Document. Каждый DocID может находиться в обоих полях.Рекурсивные запросы в SQL

Например:

MainDocID LinkedDocID 
317  3214 
7969 317 
317  11723 
317  17387 
7969 19325 
19325 19847 

я написал процедуру, которая возвращает все связанные DocIDs. Для любых DocId из моего примера тот же результат:

317 
3214 
7969 
11723 
17387 
19325 
19847 

Вот процедура:

CREATE PROCEDURE [dbo].[GetAllLinkedDocumentsForStack](@DocID int) AS BEGIN 
    create table #doc_tree (id int IDENTITY (1, 1) NOT NULL , 
     doc_id int NULL , 
     isdone int NOT NULL DEFAULT (0) 
    ) ON [PRIMARY] 

    insert into #doc_tree (doc_id) values (@DocID) 

    declare @id_header int 
    set @id_header = @DocID 

    declare c0 cursor for select doc_id from #doc_tree where isdone = 0 

    open c0 

    fetch next from c0 into @id_header 

    while @@fetch_status=0 
    begin 

     insert into #doc_tree (doc_id) 
      select LinkedDocID from DocumentLink where MainDocID = @id_header and LinkedDocID not in (select doc_id from #doc_tree) 
      union 
      select MainDocID from DocumentLink where LinkedDocID = @id_header and MainDocID not in (select doc_id from #doc_tree); 

     update #doc_tree set isdone = 1 where doc_id = @id_header 

     fetch next from c0 into @id_header 

    end 

    close c0 
    deallocate c0 

    select DocID from Document where DocID In (select Doc_ID from #doc_tree)        

    drop table #doc_tree END 

Мой вопрос: Как я могу сделать то же самое с КТР?

+1

Есть ли вероятность круговых ссылок в вашей системе (возможно, ошибка или ожидаемое поведение)? – Paolo

+0

Вы имеете в виду 2 записи, например 317 3214 и 3214 317? № – KarenD

+0

, скорее всего, произойдет с цепью: ** 1 **, 25 - 25,258 - 258,98 - 98,1908 - 1908, ** 1 **. это невозможно? не так ли? – Paolo

ответ

1

Это немного сложно с помощью CTE. Ключ при прохождении через графики находит способ предотвратить бесконечные циклы. Это происходит приближение начинка их в строку и проверка против строки для предотвращения бесконечных циклов:

with cte as (
     select @docid as docid, 
      cast(',' + cast(@docid as varchar(max)) + ',' as varchar(max)) as list 
     union all 
     select maindocid, cast(list + maindocid + ',' as varchar(max)) 
     from DocumentLink dl join 
      cte 
      on dl.linkeddocid = cte.docid 
     where cte.list not like '%,' + dl.maindocid + ',%' 
     union all 
     select linkeddocid, cast(list + linkeddocid + ',' as varchar(max)) 
     from DocumentLink dl join 
      cte 
      on dl.maindocid = cte.docid 
     where cte.list not like '%,' + dl.linkeddocid + ',%' 
    ) 
select docid 
from cte; 

Также отметим, что существует два рекурсивных компонентов, один для прогулок каждый путь по списку.

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