2008-10-10 48 views
8

我有一個SQL Server中的表,它具有Item_ID,Item_ParentID的普通樹結構。 假設我想迭代並獲取特定Item_ID的所有CHILDREN(任何級別)。在SQL Server中遞歸是否好?

遞歸似乎是這個問題的直覺候選人,我可以寫一個SQL Server函數來做到這一點。

如果我的表有許多記錄,這會影響性能嗎? 如何避免遞歸併簡單地查詢表格?請提出任何建議?

回答

4

隨着新的MS SQL 2005,你可以使用關鍵字WITH

退房this question特別this answer

使用Oracle,您可以使用CONNECT BY關鍵字來生成分層查詢(syntax)。

AFAIK與MySQL你將不得不使用遞歸。

或者你總是可以建立一個緩存表

0

也許一些更多的細節是爲了。

如果您有描述的主從關係,那麼不會有簡單的JOIN獲得您所需要的嗎?

如:

SELECT 
    SOME_FIELDS 
FROM 
    MASTER_TABLE MT 
,CHILD_TABLE CT 
WHERE CT.PARENT_ID = MT.ITEM_ID 
1

是否使用SQL 2005的記錄父 - >子的關係?

如果是這樣你可以使用公共表表達式來做到這一點。沿着這些路線的東西:

; 
with CTE (Some, Columns, ItemId, ParentId) as 
(
    select Some, Columns, ItemId, ParentId 
    from myTable 
    where ItemId = @itemID 
    union all 
    select a.Some, a.Columns, a.ItemId, a.ParentId 
    from myTable as a 
    inner join CTE as b on a.ParentId = b.ItemId 
    where a.ItemId <> b.ItemId 
) 
select * from CTE 
0

你不應該需要遞歸兒童 - 你只是看水平下方(即select * from T where ParentId = @parent) - 你只需要爲所有後代遞歸。

在SQL2005你可以得到後代,

with AllDescendants (ItemId, ItemText) as (
    select t.ItemId, t.ItemText 
     from [TableName] t 
    where t.ItemId = @ancestorId 
    union 
    select sub.ItemId, sub.ItemText 
     from [TableName] sub 
      inner join [TableName] tree 
      on tree.ItemId = sub.ParentItemId 
) 
+0

我覺得他的問題,他希望「在一個特定的水平「。除非你存儲級別數字,你怎麼知道什麼是在一個特定的水平,沒有根源= 1級,根的孩子= 2級,孩子的孩子= 3級,等等...... 不需要遞歸。但可能有多個父母。 – Cervo 2008-10-10 16:07:54

1

你將與遞歸和性能所面臨的問題是,它將會有多少次改乘返回結果。每次遞歸調用都是另一個獨立的調用,必須加入到總體結果中。

在SQL 2K5可以使用公用表表達式來處理這個遞歸:

WITH Managers AS 
( 
--initialization 
SELECT EmployeeID, LastName, ReportsTo 
FROM Employees 
WHERE ReportsTo IS NULL 
UNION ALL 
--recursive execution 
SELECT e.employeeID,e.LastName, e.ReportsTo 
FROM Employees e INNER JOIN Managers m 
ON e.ReportsTo = m.employeeID 
) 
SELECT * FROM Managers 

或另一種解決方案是層次扁平化到另一臺

Employee_Managers
經理ID(PK ,FK到Employee表)
EmployeeId(PK,FK到員工表)

米所有的父子關係的船舶將被存儲在該表中,因此,如果經理1管理經理2名管理員工3,表看起來像:

ManagerId EmployeeId 
1   2 
1   3 
2   1 

這樣的層次可以很容易地查詢:

select * from employee_managers em 
inner join employee e on e.employeeid = em.employeeid and em.managerid = 42 

這將返回有經理42.所有員工的上升空間將是更高的性能,但下行空間將被維持層次

2

作爲一般的答案,就可以做一些相當複雜的東西在SQL服務器沒有隻需要使用迭代算法,就需要遞歸。我設法在Transact SQL中做了一個XHTML解析器,它工作得非常出色。我寫的代碼優化器是在存儲過程中完成的。它不是優雅的,它更像是看着水牛做芭蕾舞。但它的工作原理。

+0

我曾經在Transact-SQL中寫過視頻播放器! :-P – 2008-10-10 14:48:54

1

Joe Celko有一個book(< - 鏈接到亞馬遜)特別是在SQL數據庫中的樹結構。雖然您需要爲您的模型遞歸,並且肯定會存在潛在的性能問題,但還有其他方法可以根據您的具體問題涉及哪些可以避免遞歸併提供更好性能的樹結構建模。

0

你並不需要在所有的遞歸.... 注意,我改變了列項ID和ItemParentID便於打字...

 
DECLARE @intLevel INT 
SET @intLevel = 1

INSERT INTO TempTable(ItemID, ItemParentID, Level) SELECT ItemID, ItemParentID, @intLevel WHERE ItemParentID IS NULL

WHILE @intLevel < @TargetLevel BEGIN SET @intLevel = @intLevel + 1 INSERT INTO TempTable(ItemID, ItemParentID, Level) SELECt ItemID, ItemParentID, @intLevel WHERE ItemParentID IN (SELECT ItemID FROM TempTable WHERE Level = @intLevel-1) -- If no rows are inserted then there are no children IF @@ROWCOUNT = 0 BREAK END

SELECt ItemID FROM TempTable WHERE Level = @TargetLevel