U kunt recursieve subqueryfactoring gebruiken (ook bekend als een recursieve 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
Het is eigenlijk het doorlopen van uw handmatige stappen. Het ankerlid is uw eerste handmatige stap, het instellen van x
en y
beide op nul voor de eerste rij. Het recursieve lid voert vervolgens de door u opgegeven berekening uit. (Je kunt niet verwijzen naar de nieuw berekende x
waarde bij het berekenen van de y
. van die rij , dus je moet dat herhalen als (tmp.n * 2) + r.y - 1
). De rn
is alleen om de rijen te ordenen op ID, terwijl het gemakkelijker wordt om de volgende rij te vinden - zodat u kunt zoeken naar rn + 1
in plaats van direct de volgende hoogste ID-waarde te vinden.
Er is geen significant prestatieverschil met uw voorbeeldgegevens, maar met duizend rijen toegevoegd duurt de modelclausule ongeveer 5 seconden en duurt de recursieve CTE ongeveer 1 seconde; met nog eens duizend rijen duurt het model ~20 seconden en de CTE ~3 seconden; met nog eens duizend rijen duurde het model ~40 seconden en de CTE ~6 seconden; en met nog eens duizend rijen (dus 4.008 in totaal) duurde het model ~75 seconden en de CTE ~10 seconden. (Ik verveelde me bij het wachten op de modelversie met meer rijen dan dat; doodde het na vijf minuten met 10.000). Ik kan niet echt zeggen hoe dit zal presteren met uw echte gegevens, maar op basis daarvan is het waarschijnlijk het proberen waard.