2008-10-10 51 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