2017-02-10 116 views
1

我有用戶和他們的經理表:SQL - 如何避免最大遞歸的遞歸查詢使用CTE

|ID | Title  | Manager | 
|1 | Manager 1 | 4  | 
|2 | Manager 2 | 1  | 
|3 | Manager 3 | 1  | 
|4 | Manager 4 | 2  | 
|5 | Manager 5 | 3  | 
... 
|10 | Manager 10| NULL | 
|11 | Manager 11| 10  | 

我有一個返回所有經理的ID在層次結構開始用一個簡單的遞歸查詢給出最高管理者ID及以下:

DECLARE @Managers TABLE (ManagerID int) 
DECLARE @ManagerID int = 1 
     BEGIN 
      ;WITH ManagerCTE AS (
           SELECT ID FROM tblUsers WHERE ID = @ManagerID 
           UNION ALL 
           SELECT chld.ID FROM tblUsers chld 
           INNER JOIN ManagerCTE items ON chld.Manager = items.ID 
           ) 
      INSERT INTO @Managers 
      SELECT ID FROM ManagerCTE 
     END 
SELECT * FROM @Managers 

而且,如果經理層級結構組織良好,但在某些情況下,我們已經雜亂無章的結構,其中下部經理恰好是上經理的經理: enter image description here

在這種情況下,遞歸查詢進入一個循環和最大遞歸100被語句完成之前耗盡。我需要將這些管理器從查詢中排除,如果它們已被選中到結果表中以避免這些循環。

我該怎麼做?

另一種可能的解決方案是在達到某個級別或它時(例如,5)從遞歸中退出。但選項(maxrecursion 5)僅設置限制,並且如果達到限制,則查詢會產生錯誤。

如何退出遞歸併繼續執行沒有任何錯誤的腳本?

+0

如果您關注是關於限制100你可以給最大限制'從ManagerCTE 選項(maxrecursion 0)' –

+0

不應該在數據庫中修復這個問題嗎?在我看來,這是一種不能(或者至少不應該)存在的情況。 – HoneyBadger

+0

如果我放置(maxrecursion 0),這將不會被修復,因爲我們會得到一個無限循環。 –

回答

0

WITH試試這個:

SELECT ID, ID::text as ids FROM tblUsers WHERE ID = @ManagerID 
UNION ALL 
SELECT chld.ID FROM tblUsers chld, items.ids || ',' || chld.ID::text as ids 
INNER JOIN ManagerCTE items ON chld.Manager = items.ID AND chld.ID::text not like '%'||items.ids||'%' 

守則下PostgreSQL的寫入。根據你的數據庫更改字符串的功能。

+0

這是行不通的,因爲我收到一個錯誤:「公用表表達式'ManagerCTE'的遞歸成員有多個遞歸引用」 –

+0

對不起,我需要記住的一個時刻,我已經完成了這項工作 –

+0

您使用哪個數據庫? –

1

至於說在我的意見,你可以檢查訪問節點as I do it here通過將它們存儲在一個成長路徑字符串,或者你可以用遞歸CTE這樣的限制遞歸的深度:

SELECT 1 AS CurrentLevel,ID FROM tblUsers WHERE ID = @ManagerID 
UNION ALL 
SELECT items.CurrentLevel+1,chld.ID FROM tblUsers chld 
INNER JOIN ManagerCTE items ON chld.Manager = items.ID 
WHERE items.CurrentLevel<=5 
+0

謝謝,我可能會限制遞歸的深度。 –