2012-01-16 19 views
5

Attualmente abbiamo una stored procedure che restituisce i dati da una tabella in esso è lo schema originale di fare qualcosa di simile:Come limitare la profondità della ricorsione CTE ma selezionare la tabella generica?

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 

Questo è bello, perché non importa quanto le modifiche dello schema tavolo, finché ci sono [ Id] e [ParentId] colonne, non dovrò aggiornare questa stored procedure. Mi piacerebbe fare qualcosa di simile, ma anche essere in grado di specificare la profondità della ricorsione in modo dinamico. L'unico modo che ho visto per farlo è quello di aggiungere un livello/identificatore di profondità in questo modo:

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 

Questo funziona bene, ma toglie il grande vantaggio della query precedente in quanto la selezione * alla fine darà anche io il livello. C'è un altro modo per farlo quando posso specificare un livello, ma anche selezionare genericamente tutte le colonne dalla tabella? Grazie in anticipo.

risposta

12

Se tutto quello che vuole fare con il vostro campo di livello è limite al numero di ricorsione, si dovrebbe essere in grado di utilizzare un MAXRECURSION query hint, qualcosa di simile:

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:

In risposta alla la domanda nei commenti, no, non è possibile sopprimere l'errore che si ottiene quando si ricorre più volte di quanto consentito dall'impostazione MAXRECURSION. Se ho capito bene, si potrebbe fare qualcosa di simile:

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; 

questo dovrebbe essere altrettanto generico come quello che hai sopra, a patto che non hai intenzione di cambiare i campi chiave gerarchiche o primari.

+0

Sembra generare un errore quando viene raggiunto il limite. C'è un modo per fermarlo basato su MAXRECURSION, ma continuare a usare i risultati? – Ocelot20

+0

Risposte sopra (con un altro suggerimento) ... – mwigdahl