sql >> Databasteknik >  >> RDS >> Sqlserver

Förstå den rekursiva CTE-avslutningskontrollen

Här är ett bättre exempel med datum. Antag att vi vill bygga en tabell över datum. 1 rad för varje månad för år 2017. Vi skapar en @startDate som ankare och @endDate som terminator. Vi ställer in dessa på 12 månaders mellanrum, eftersom vi vill ha ett enda år. Sedan kommer rekursionen att lägga till en månad via DATEADD funktion till @startDate tills terminatorn är uppfylld i WHERE klausul. Vi vet att det kommer att ta 11 rekursioner för att nå 12 månader... det vill säga 11 månader + startdatumet. Om vi ​​ställer in MAXRECURSION till något mindre än 11, då kommer det att misslyckas eftersom 11 behövs för att uppfylla WHERE klausul i vår rekursiva CTE , det är terminatorn..

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 din fråga skulle en enkel sammanfogning räcka.

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

Jag ser dock att du försöker returnera detta i ett udda format, som bör hanteras i vilket rapporteringsprogram du än använder. Detta skulle få dig nära utan rekursioner.

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



  1. Sorterbara UUID och åsidosättande ActiveRecord::Base

  2. Konfigurera Databas Mail i SQL Server

  3. förstå Java JDBC-fel

  4. looping mysql_real_connect eller vad