2013-04-18 84 views
3

我有一個表FolderXDoc無限循環:TSQL:處理數據

CREATE TABLE [dbo].[FolderXDoc](
[fldid] [int] NOT NULL, 
[Xorder] [int] NOT NULL, 
[docid] [int] NOT NULL, 
CONSTRAINT [FolderXDoc$pk] PRIMARY KEY CLUSTERED 
(
[fldid] ASC, 
[Xorder] ASC, 
[docid] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

我的應用程序允許在該表中循環引用,所以下面的數據是正確的:

fldid|Xorder|docid 
1|1|2 
2|1|3 
3|1|4 
4|1|2 

所以文件夾1中包含文件夾2包含文件夾3.文件夾3包含文件夾4.文件夾4包含文件夾2,因此我們有一個循環(1/2/3/4/2/3/4/2/3/4/...)

現在我想檢索一個文件夾中的所有元素遞歸。我在CTE上試了這個,但由於數據的循環,這不起作用。我想在檢測到循環時停止遞歸。所以當我檢索1的包含元素時,我期望結果集(2,3,4)。

我試圖與用戶定義的函數:

CREATE FUNCTION [dbo].[DocChildren](@fldid int) 
RETURNS TABLE 
AS 
RETURN 
(
    WITH n AS 
      (SELECT f.fldid, f.docid 
      FROM folderxdoc f where f.fldid = @fldid 
      UNION ALL 

      SELECT n.fldid, nplus1.docid 
      FROM folderxdoc as nplus1, n 
       WHERE n.docid = nplus1.fldid and n.docid != @fldid) 

    SELECT docid FROM n 
) 

的函數處理的起始ID的循環迴路,而不是當該週期中所包含的元素髮生。 我能做些什麼來解決這個問題?

感謝您的幫助!

+2

你想輸出什麼,當你碰到這些無限循環中的一個?你想讓它顯示第一個完整的鏈?在你上面的例子中,你想要1/2/3/4還是1/2/3/4/2/3/4還是別的? –

+3

您可以在CTE中找到檢測循環的示例[此處](http://stackoverflow.com/questions/15080922/infinite-loop-cte-with-option-maxrecursion-0/15081353#15081353)。它涉及在遞歸和測試重複條目期間組裝路徑。 – HABO

+0

@註冊用戶:感謝您的反饋。我編輯了這個問題。對於包含在1中的所有元素,我的預期結果集爲(2,3,4)。 – carlptr

回答

1

我用@HaBo的提示解決了這個問題。

我在遞歸期間組裝了路徑並檢查了重複條目。您可以在這裏找到結果查詢: http://sqlfiddle.com/#!3/cc8b3/1

WITH n AS 
     (SELECT f.fldid, f.docid, ',' + cast(f.fldid as varchar(max)) + ',' levels 
     FROM folderxdoc f where f.fldid = 1 
     UNION ALL 

     SELECT n.fldid, nplus1.docid,n.levels+ cast(n.docid as varchar(max)) + ',' levels 
     FROM folderxdoc as nplus1, n 
      WHERE n.docid = nplus1.fldid AND 
      n.levels not like ('%,' + cast(nplus1.docid as varchar(max)) + ',%') 
     ) 

SELECT fldid, docid, levels FROM n 
1

也許一個臨時表來標記一個節點已被訪問可能會有所幫助。

基本上,當您訪問每個節點時,將其推入臨時表並檢查每個節點與臨時表。當您找到現有節點時停止。

可能需要使用遊標來實現這一點,儘管這可能是糟糕的。