Potresti usare fattorizzazione ricorsiva di sottoquery (noto anche come CTE ricorsivo):
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
Fondamentalmente sta seguendo i tuoi passaggi manuali. Il membro anchor è il tuo primo passaggio manuale, l'impostazione di x
e y
entrambi a zero per la prima riga. Il membro ricorsivo esegue quindi il calcolo specificato. (Non puoi fare riferimento al nuovo x
calcolato valore durante il calcolo di y
di quella riga , quindi devi ripeterlo come (tmp.n * 2) + r.y - 1
). Il rn
serve solo a mantenere gli ordini delle righe per ID mentre è più facile trovare la riga successiva, così puoi cercare rn + 1
invece di trovare direttamente il valore ID successivo più alto.
Non c'è alcuna differenza di prestazioni significativa con i dati di esempio, ma con un migliaio di righe aggiunte la clausola del modello richiede circa 5 secondi e il CTE ricorsivo richiede circa 1 secondo; con altre mille righe il modello impiega ~20 secondi e il CTE impiega ~3 secondi; con altre mille righe il modello ha impiegato circa 40 secondi e il CTE ha impiegato circa 6 secondi; e con altre mille righe (quindi 4.008 in totale) il modello ha impiegato circa 75 secondi e il CTE ha impiegato circa 10 secondi. (Mi sono annoiato ad aspettare la versione del modello con più righe di quella; l'ho ucciso dopo cinque minuti con 10.000). Non posso davvero dire come funzionerà con i tuoi dati reali, ma su questa base, probabilmente vale la pena provare.