2012-01-16 103 views
5

目前我们已经从一个表中返回数据的存储过程,通过做这样的事情的原始架构:如何限制CTE递归深度但选择通用表?

WITH CTE AS 
(
    -- Start CTE off by selecting the id that was provided to stored procedure. 
    SELECT * 
    FROM [dbo].[TestTable] 
    WHERE [Id] = 1 
    -- Recursively add tasks that are children of records already found in previous iterations. 
    UNION ALL 
    SELECT t.* 
    FROM [dbo].[TestTable] as t 
    INNER JOIN CTE as tcte 
     ON t.[ParentId] = tcte.[Id] 
)   
SELECT * 
FROM CTE 

这是很好的,因为无论表模式的变化,只要有多大[ Id]和[ParentId]列,我不必更新此存储过程。我想要做类似的事情,但也能够动态指定递归的深度。我已经看到了这样做的唯一方法是增加一个等级/深度识别,像这样:

WITH CTE AS 
(
    -- Start CTE off by selecting the task that was provided to stored procedure. 
    SELECT *, 0 as [Level] 
    FROM [dbo].[TestTable] 
    WHERE [Id] = 1 
    -- Recursively add tasks that are children of parent tasks that have already been found in previous iterations. 
    UNION ALL 
    SELECT t.*, [Level] + 1 
    FROM [dbo].[TestTable] as t 
    INNER JOIN CTE as tcte 
     ON t.[ParentId] = tcte.[Id] 
    WHERE [Level] < 2 
)   
SELECT * 
FROM CTE 

这种运作良好,但带走,因为在年底选择*会给上一个查询的重大利好我也是这个水平。有没有其他的方式可以指定一个关卡,但是也可以一般地选择表中的所有列?提前致谢。

回答

12

如果你想与你的水平场做的是限制递归次数,你应该能够使用MAXRECURSION query hint,是这样的:

WITH Department_CTE AS 
(
    SELECT 
     DepartmentGroupKey, 
     ParentDepartmentGroupKey, 
     DepartmentGroupName 
    FROM dimDepartmentGroup 
    WHERE DepartmentGroupKey = 2 
    UNION ALL 
    SELECT 
     Child.DepartmentGroupKey, 
     Child.ParentDepartmentGroupKey, 
     Child.DepartmentGroupName 
    FROM Department_CTE AS Parent 
     JOIN DimDepartmentGroup AS Child 
      ON Parent.ParentDepartmentGroupKey = Child.DepartmentGroupKey 
) 
SELECT * FROM Department_CTE 
OPTION (MAXRECURSION 2) 

编辑:

在回答在评论中的问题,不,你不能抑制你的递归次数多于MAXRECURSION设置允许的错误。如果我理解正确的话,你可以做这样的事情:

WITH CTE AS 
(
    -- Start CTE off by selecting the task that was provided to stored procedure. 
    SELECT Id, 0 as [Level] 
    FROM [dbo].[TestTable] 
    WHERE [Id] = 1 
    -- Recursively add tasks that are children of parent tasks that have already been found in previous iterations. 
    UNION ALL 
    SELECT t.Id, [Level] + 1 
    FROM [dbo].[TestTable] as t 
    INNER JOIN CTE as tcte 
     ON t.[ParentId] = tcte.[Id] 
    WHERE [Level] < 2 
), 
CTE2 AS 
(
    SELECT TestTable.* 
    FROM CTE 
     INNER JOIN TestTable ON CTE.Id = TestTable.Id 
) 
SELECT * FROM CTE2; 

这应该是平等的,你有什么上面,假设你没有改变分层或主键字段计划为通用。

+0

达到限制时似乎会出现错误。有什么办法让它停止基于MAXRECURSION,但继续使用结果? – Ocelot20 2012-01-16 19:45:33

+0

回答上面(有另一个建议)... – mwigdahl 2012-01-16 19:55:54