Du kan bruge rekursiv subquery factoring (også kendt som en rekursiv 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
Det er dybest set at gå gennem dine manuelle trin. Ankerelementet er dit første manuelle trin, idet du indstiller x
og y
begge til nul for den første række. Det rekursive medlem foretager derefter den udregning, du har angivet. (Du kan ikke henvise til den nyberegnede x
værdi ved beregning af denne rækkes y
, så du skal gentage det som (tmp.n * 2) + r.y - 1
). rn
er bare at beholde rækkernes rækkefølger efter ID og samtidig gøre det nemmere at finde den næste række - så du kan kigge efter rn + 1
i stedet for at finde den næsthøjeste ID-værdi direkte.
Der er ingen signifikant ydelsesforskel med dine prøvedata, men med tusind rækker tilføjet tager modelklausulen omkring 5 sekunder, og den rekursive CTE tager omkring 1 sekund; med yderligere tusind rækker tager modellen ~20 sekunder, og CTE'en tager ~3 sekunder; med yderligere tusind rækker tog modellen ~40 sekunder og CTE tog ~6 sekunder; og med yderligere tusinde rækker (altså 4.008 i alt) tog modellen ~75 sekunder og CTE tog ~10 sekunder. (Jeg kedede mig af at vente på modelversionen med flere rækker end det; slog den ihjel efter fem minutter med 10.000). Jeg kan ikke rigtig sige, hvordan dette vil fungere med dine rigtige data, men på det grundlag er det nok værd at prøve.