Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Comprendre le contrôle de terminaison CTE récursif

Voici un meilleur exemple utilisant des dates. Supposons que nous voulions construire une table de dates. 1 ligne pour chaque mois de l'année 2017. Nous créons un @startDate comme ancre et @endDate comme terminateur. Nous les avons mis à 12 mois d'intervalle, puisque nous voulons une seule année. Ensuite, la récursivité ajoutera un mois via le DATEADD fonction à @startDate jusqu'à ce que le terminateur soit rencontré dans le WHERE clause. Nous savons qu'il faudra 11 récursions pour atteindre 12 mois... c'est-à-dire 11 mois + la date de début. Si nous définissons le MAXRECURSION à quelque chose de moins que 11, alors il échouera puisque 11 sont nécessaires pour remplir le WHERE clause dans notre CTE récursif , c'est le terminateur..

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

Pour votre requête, une simple jointure suffirait.

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

Cependant, je vois que vous essayez de renvoyer ceci dans un format étrange, qui devrait être géré dans n'importe quelle application de rapport que vous utilisez. Cela vous rapprocherait sans récursivité.

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