2012-01-16 23 views
5

Actualmente tenemos un procedimiento almacenado que devuelve datos de una tabla en la que es esquema original al hacer algo como esto:Cómo limitar la profundidad de la recursión CTE pero seleccionar la tabla genérica?

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 

Esto es bueno, porque no importa cómo los cambios de esquema de la tabla, siempre y cuando no son [ Id] y [ParentId] columnas, no tendré que actualizar este procedimiento almacenado. Me gustaría hacer algo similar, pero también ser capaz de especificar la profundidad de la recursión de forma dinámica. La única forma que he visto hacer esto es añadir un identificador de nivel/Profundidad de esta manera:

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 

Esto funciona bien, pero se lleva la gran ventaja de la consulta anterior, ya que la selección de * al final dará yo también el nivel. ¿Hay alguna otra forma de hacer esto donde podría especificar un nivel, pero también seleccionar genéricamente todas las columnas de la tabla? Gracias por adelantado.

Respuesta

12

Si todo lo que quiere hacer con su campo de nivel es limitar el número de recurrencias, usted debe ser capaz de utilizar una MAXRECURSION query hint, algo como esto:

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) 

Editar:

En respuesta a la pregunta en los comentarios, no, no se puede suprimir el error que se produce cuando se repiten más veces de las que permite la configuración de MAXRECURSIÓN. Si he entendido bien, usted podría hacer algo como esto:

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; 

Esto debería ser igualmente tan genérico como lo que tiene encima, suponiendo que no está pensando en el cambio de los campos clave jerárquicas o primarios.

+0

Parece que se produce un error cuando se alcanza el límite. ¿Hay alguna forma de detenerlo basado en MAXRECURSION, pero continuar usando los resultados? – Ocelot20

+0

Respondido arriba (con otra sugerencia) ... – mwigdahl

Cuestiones relacionadas