EDYTUJ
Kiedy przeczytasz dokumentację CTE dotyczącą rekurencji, zauważysz, że ma ona pewne ograniczenia, takie jak brak możliwości użycia podzapytań, grupowanie według, top. Wszystko to obejmuje wiele rzędów. Od ograniczonego testowania i sprawdzania planu wykonania, a także testowania tego zapytania
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
Mogę tylko stwierdzić:
- Row_Number() działa w CTE, gdy inne tabele są łączone w celu uzyskania wielowierszowego zestawu wyników
- Z wyników numeracji jasno wynika, że CTE są przetwarzane w jednym wierszu we wszystkich iteracjach, wiersz po wierszu, a nie wiele wierszy po wielu wierszach, mimo że wydaje się, że wszystkie wiersze są wykonywane jednocześnie. To wyjaśniałoby, dlaczego żadna z funkcji, które mają zastosowanie do operacji wielowierszowych, nie jest dozwolona dla rekurencyjnego CTE.
Chociaż łatwo doszedłem do tego wniosku, ktoś najwyraźniej poświęcił dużo więcej czasu na wyjaśnij to w nieznośnych szczegółach tylko 17 miesięcy temu...
Innymi słowy, taka jest natura implementacji SQL Server rekurencyjne CTE, więc funkcje okienkowe nie będą działać tak, jak tego oczekujesz.
Dla dobra innych wynik jest następujący:
a b c d
----------- ----------- ----------- -----------
1 1 1 2
1 2 1 2
2 3 1 2
2 4 1 2
Podczas gdy oczekujesz, że c będzie zawierać 1,2,1,2 zamiast 1,1,1,1. To z pewnością wygląda na to, że może to być błąd, ponieważ nie ma dokumentacji mówiącej, że funkcje okienkowe nie powinny działać w rekurencyjnej części CTE.
Uwaga:row_number() zwraca bigint, więc możesz rzutować tylko kotwicę(c) jako bigint.
Ponieważ każda iteracja zwiększa d, możesz wykonać okienkowanie na zewnątrz.
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
EDYTUJ — wgląd
Odpowiadając na kolejne pytanie , grałem trochę więcej z rekurencyjnym CTE. Jeśli uruchomisz go bez końcowego ORDER BY, możesz zobaczyć, jak SQL Server zbliża się do rekursji. Interesujące jest to, że w tym przypadku cofa się, a następnie wykonuje pełną rekurencję do pierwszej głębokości w każdym wierszu.
Przykładowa tabela
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'
Zapytanie rekurencyjne
;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
Wynik pokazuje kotwicę CTE przetworzoną w pierwszej iteracji, a następnie z dowolnego powodu każdy wiersz w zestawie zakotwiczeń jest powtarzany do końca (najpierw na głębokość) przed przetworzeniem innych wierszy.
Jednak ma swoje dziwne zastosowania, jak ta odpowiedź programy