Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Comprensione del controllo ricorsivo di terminazione CTE

Ecco un esempio migliore usando le date. Supponiamo di voler costruire una tabella di date. 1 riga per ogni mese dell'anno 2017. Creiamo un @startDate come anchor e @endDate come terminatore. Abbiamo impostato questi a 12 mesi di distanza, dal momento che vogliamo un solo anno. Quindi, la ricorsione aggiungerà un mese tramite il DATEADD funzione al @startDate fino a quando il terminatore non viene soddisfatto in WHERE clausola. Sappiamo che ci vorranno 11 ricorsioni per raggiungere 12 mesi... cioè 11 mesi + la data di inizio. Se impostiamo il MAXRECURSION a qualcosa di meno di 11, allora fallirà poiché 11 sono necessari per soddisfare il WHERE clausola nel nostro CTE ricorsivo , questo è il terminatore..

declare @startDate datetime = '20170101'
declare @endDate datetime = '20171201'

;WITH Months
as
(
    SELECT @startDate as TheDate       --anchor
    UNION ALL
    SELECT DATEADD(month, 1, TheDate)  --recursive
    FROM Months
    WHERE TheDate < @endDate           --terminator... i.e. continue until this condition is met

)


SELECT * FROM Months OPTION (MAXRECURSION 10) --change this to 11

Per la tua richiesta sarebbe sufficiente un semplice join.

select 
  firstName
  ,lastName
  ,orderDate
  ,productID
from
  customers c
inner join
  orders o on o.customerID = c.id

Tuttavia, vedo che stai cercando di restituire questo in un formato strano, che dovrebbe essere gestito in qualsiasi applicazione di segnalazione che stai utilizzando. Questo ti porterebbe vicino senza ricorsione.

with cte as(
select 
  firstName
  ,lastName
  ,orderDate
  ,productID
  ,dense_rank() over(order by c.id) as RN
from
  customers c
inner join
  orders o on o.customerID = c.id)


select distinct
  firstName
  ,lastName
  ,null
  ,null
  ,RN
from 
  cte
union all
select
  ''
  ,''
  ,orderDate
  ,productID
  ,RN
from 
  cte
order by RN, firstName desc