2012-01-16 2 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) 

Edit:

В ответ на вопрос в комментариях, нет, вы не можете подавить ошибку, которую вы получаете, когда рекурсируете больше раз, чем позволяет настройка 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

+0

Ответил выше (с другим предложением) ... – mwigdahl

Смежные вопросы