我在SQL Server中有一个表,它具有Item_ID,Item_ParentID的常规树结构。 假设我想迭代并获取特定Item_ID(在任何级别)的所有CHILDREN。
递归似乎是这个问题的直观候选者,我可以编写一个SQL Server函数来执行此操作。
如果我的表有很多记录,这会影响性能吗? 如何避免递归并简单地查询表?请提出任何建议吗?
答案 0 :(得分:5)
使用新的MS SQL 2005,您可以使用WITH
关键字
结帐this question,特别是this answer。
使用Oracle,您可以使用CONNECT BY
关键字生成分层查询(syntax)。
使用MySQL的AFAIK,你必须使用递归。
或者,您始终可以为记录父级>子关系
构建缓存表答案 1 :(得分:2)
作为一般答案,可以在SQL Server中做一些非常复杂的事情,通常需要递归,只需使用迭代算法。我设法在Transact SQL中做了一个非常好的XHTML解析器。我写的代码美化是在存储过程中完成的。它不是优雅的,它更像是看水牛做芭蕾舞。但它确实有效。
答案 2 :(得分:1)
您使用的是SQL 2005吗?
如果是这样,您可以使用Common Table Expressions。这些方面的东西:
;
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
答案 3 :(得分: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
ManagerId(PK,FK到员工表)
EmployeeId(PK,FK到员工表)
所有父子关系船都将存储在此表中,因此如果Manager 1管理Manager 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的员工回归。上行将是更好的表现,但缺点是维持层次结构
答案 4 :(得分:1)
Joe Celko有一个book(&lt; - 亚马逊链接),专门针对SQL数据库中的树结构。虽然您需要递归模型,并且肯定存在潜在的性能问题,但还有其他方法可以根据您的具体问题进行建模树形结构,从而避免递归并提供更好的性能。
答案 5 :(得分:0)
也许还有一些细节。
如果你描述了一个主 - 细节关系,那么简单的JOIN不会得到你需要的吗?
如:
SELECT
SOME_FIELDS
FROM
MASTER_TABLE MT
,CHILD_TABLE CT
WHERE CT.PARENT_ID = MT.ITEM_ID
答案 6 :(得分: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
)
答案 7 :(得分:0)
根本不需要递归.... 注意,我将列更改为ItemID和ItemParentID以便于输入...
DECLARE @intLevel INT SET @intLevel = 1INSERT 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