Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Verstehen der rekursiven CTE-Terminierungsprüfung

Hier ist ein besseres Beispiel mit Datumsangaben. Angenommen, wir möchten eine Datumstabelle erstellen. 1 Zeile für jeden Monat für das Jahr 2017. Wir erstellen ein @startDate als Anker und @endDate als Terminator. Wir legen diese auf 12 Monate auseinander, da wir ein einzelnes Jahr wollen. Dann fügt die Rekursion über DATEADD einen Monat hinzu Funktion zum @startDate bis das Abschlusszeichen im WHERE getroffen wird Klausel. Wir wissen, dass es 11 Rekursionen braucht, um 12 Monate zu erreichen ... also 11 Monate + das Startdatum. Wenn wir MAXRECURSION setzen zu etwas weniger als 11, dann schlägt es fehl, da 11 benötigt werden, um WHERE zu erfüllen -Klausel in unserem rekursiven CTE , das ist der Terminator..

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

Für Ihre Anfrage würde ein einfacher Join ausreichen.

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

Ich sehe jedoch, dass Sie versuchen, dies in einem seltsamen Format zurückzugeben, das in jeder Berichtsanwendung verarbeitet werden sollte, die Sie verwenden. Dies würde Sie ohne Rekursion nahe bringen.

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