Sql server SQL中的递归查询

Sql server SQL中的递归查询,sql-server,Sql Server,我有两个表:Document和DocumentLink。 DocumentLink有两个字段:MainDocID和LinkedDocID,它们用文档表中的DocID值填充。每个DocID可以在两个字段中 例如: MainDocID LinkedDocID 317 3214 7969 317 317 11723 317 17387 7969 19325 19325 19847 我编写了返回所有链接文档ID的过程。对于我的示例中的

我有两个表:Document和DocumentLink。 DocumentLink有两个字段:MainDocID和LinkedDocID,它们用文档表中的DocID值填充。每个DocID可以在两个字段中

例如:

MainDocID LinkedDocID  
317     3214  
7969    317  
317     11723  
317     17387  
7969    19325  
19325   19847  
我编写了返回所有链接文档ID的过程。对于我的示例中的任何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

我的问题是:如何使用CTE进行同样的操作

这对于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;

还请注意,有两个递归组件,一个用于遍历列表。

系统中是否存在循环引用的可能性(可能是错误或预期行为)?您是指2条记录,例如317 3214和3214 317?不,这更可能发生在连锁店:1,25-25258-258,98-981908-1908,1。这不可能吗?不可能发生这种情况?客户根据现有文档创建文档,但不排除这种情况