sql >> Base de Datos >  >> RDS >> Sqlserver

cte recursivo con funciones de clasificación

EDITAR

Cuando lea la documentación de CTE con respecto a la recursividad, notará que tiene algunos límites, como no poder usar subconsultas, agrupar por, top. Todos estos involucran múltiples filas. De pruebas limitadas y verificación del plan de ejecución, así como la prueba de esta consulta

with cte as (
  select 1 a, 1 b union all select 1, 2 union all select 1, 3 union all select 2, 4
)
, rcte (a, b, c, d) as (
  select a, b, cast(0 as int), 1 
  from cte
  union all
  select r.a, cte.b, cast(ROW_NUMBER() over (order by r.b) as int), r.d+1
  from rcte r inner join cte on cte.a=r.a
  where r.d < 2
)
select * 
from rcte
where d=2
order by a, b

Solo puedo concluir:

  1. Row_Number() funciona en un CTE, cuando se unen otras tablas para producir un conjunto de resultados de varias filas
  2. A partir de los resultados de la numeración, está claro que los CTE se procesan en una sola fila a través de todas las iteraciones, fila por fila en lugar de fila por fila, aunque parece iterar todas las filas simultáneamente. Esto explicaría por qué cualquiera de las funciones que se aplican a las operaciones de varias filas no están permitidas para CTE recursivo.

Aunque llegué a esta conclusión fácilmente, obviamente alguien se tomó mucho más tiempo para explícalo con insoportable detalle solo Hace 17 meses...

En otras palabras, esta es la naturaleza de la implementación de SQL Server del CTE recursivo, por lo que las funciones de ventana no funcionarán de la forma esperada.

Para beneficio de los demás, el resultado es:
a           b           c           d
----------- ----------- ----------- -----------
1           1           1           2
1           2           1           2
2           3           1           2
2           4           1           2

Mientras que espera que c contenga 1,2,1,2 en lugar de 1,1,1,1. Esto ciertamente parece que podría ser un error, ya que no hay documentación que diga que las funciones de ventanas no deberían funcionar en la parte recursiva de un CTE.

Nota:row_number() devuelve bigint, por lo que puede convertir solo el ancla (c) como bigint.

Dado que cada iteración aumenta d, podría realizar la ventana en el exterior.

with cte as (
  select 1 a, 1 b union all select 1, 2 union all select 2, 3 union all select 2, 4
)
, rcte (a, b, d) as (
  select a, b, 1 
  from cte
  union all
  select a, b, d+1
  from rcte
  where d < 2
)
select a,b, ROW_NUMBER() over (partition by a,d order by b) c,d
from rcte
--where d=2
order by d, a, b

EDITAR:información

Mientras respondía otra pregunta , jugué un poco más con CTE recursivo. Si lo ejecuta sin el ORDER BY final, puede ver cómo SQL Server se acerca a la recursividad. Es interesante que va hacia atrás en este caso, luego hace una recursión de profundidad completa en cada fila.

Tabla de muestra

create table Testdata(SomeID int, OtherID int, Data varchar(max))
insert Testdata select 1, 9, '18,20,22,alpha,beta,gamma,delta'
insert Testdata select 2, 6, ''
insert Testdata select 3, 8, '11,12,.'
insert Testdata select 4, 7, '13,19,20,66,12,232,1232,12312,1312,abc,def'
insert Testdata select 5, 8, '17,19'

Una consulta recursiva

;with tmp(SomeID, OtherID, DataItem, Data) as (
select SomeID, OtherID, LEFT(Data, CHARINDEX(',',Data+',')-1),
    STUFF(Data, 1, CHARINDEX(',',Data+','), '')
from Testdata
union all
select SomeID, OtherID, LEFT(Data, CHARINDEX(',',Data+',')-1),
    STUFF(Data, 1, CHARINDEX(',',Data+','), '')
from tmp
where Data > ''
)
select SomeID, OtherID, DataItem, Data
from tmp
-- order by SomeID

El resultado muestra el ancla CTE procesada en la iteración uno, luego por cualquier motivo cada fila en el conjunto de anclas se repite hasta su finalización (primero en profundidad) antes de procesar otras filas.

Sin embargo, tiene sus usos extraños, como esta respuesta espectáculos