Możesz użyć rekurencyjnego faktoringu podzapytań (znane również jako rekurencyjne CTE):
with tmp as (
select t.*,
row_number() over (order by t.id) as rn
from t
),
r (id, n, x, y, rn) as (
select id, n, 0, 0, rn
from tmp
where rn = 1
union all
select tmp.id, tmp.n, r.y - 1, (tmp.n * 2) + r.y - 1, tmp.rn
from r
join tmp on tmp.rn = r.rn + 1
)
select id, n, x, y
from r
order by rn;
ID N X Y
---------- ---------- ---------- ----------
2 0 0 0
3 1 -1 1
5 1 0 2
7 2 1 5
11 3 4 10
13 5 9 19
17 8 18 34
19 13 33 59
To w zasadzie przejście przez twoje ręczne kroki. Element zakotwiczenia to pierwszy ręczny krok, ustawiając x
i y
oba do zera w pierwszym rzędzie. Rekurencyjny element członkowski następnie wykonuje określone obliczenia. (Nie możesz odwołać się do nowo obliczonego x
wartość podczas obliczania y
tego wiersza , więc musisz to powtórzyć jako (tmp.n * 2) + r.y - 1
). rn
jest po prostu utrzymanie kolejności wierszy według identyfikatora, jednocześnie ułatwiając znalezienie następnego wiersza - możesz więc szukać rn + 1
zamiast bezpośrednio znaleźć kolejną najwyższą wartość identyfikatora.
Nie ma znaczącej różnicy wydajności z przykładowymi danymi, ale po dodaniu tysiąca wierszy klauzula modelu zajmuje około 5 sekund, a rekurencyjne CTE zajmuje około 1 sekundy; przy kolejnym tysiącu wierszy model zajmuje ~20 sekund, a CTE ~3 sekundy; przy kolejnym tysiącu rzędów model zajął ~40 sekund, a CTE ~6 sekund; a przy kolejnym tysiącu rzędów (w sumie 4008) model zajął ~75 sekund, a CTE ~10 sekund. (Znudziło mnie czekanie na wersję modelu z większą liczbą rzędów; zabiłem ją po pięciu minutach z 10 000). Naprawdę nie mogę powiedzieć, jak to będzie działać z twoimi prawdziwymi danymi, ale na tej podstawie prawdopodobnie warto spróbować.