Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Entendendo a verificação de terminação CTE recursiva


Aqui está um exemplo melhor usando datas. Suponha que queremos construir uma tabela de datas. 1 linha para cada mês do ano de 2017. Criamos um @startDate como âncora e @endDate como o terminador. Definimos isso com 12 meses de intervalo, já que queremos um único ano. Em seguida, a recursão adicionará um mês por meio do DATEADD função para o @startDate até que o terminador seja encontrado no WHERE cláusula. Sabemos que serão necessárias 11 recursões para atingir 12 meses... ou seja, 11 meses + a data de início. Se definirmos o MAXRECURSION para algo menor que 11, ele falhará, pois 11 são necessários para preencher o WHERE cláusula em nosso CTE recursivo , que é o terminador ..
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

Para sua consulta, uma junção simples seria suficiente.
select 
  firstName
  ,lastName
  ,orderDate
  ,productID
from
  customers c
inner join
  orders o on o.customerID = c.id

No entanto, vejo que você está tentando retornar isso em um formato estranho, que deve ser tratado em qualquer aplicativo de relatório que você esteja usando. Isso o aproximaria sem recursão.
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