Vous pouvez utiliser la la factorisation récursive des sous-requêtes (également appelé CTE récursif) :
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
Il s'agit essentiellement de suivre vos étapes manuelles. Le membre d'ancrage est votre première étape manuelle, la définition de x
et y
les deux à zéro pour la première ligne. Le membre récursif effectue ensuite le calcul que vous avez spécifié. (Vous ne pouvez pas vous référer au nouveau x
calculé valeur lors du calcul de y
de cette ligne , vous devez donc répéter cela sous la forme (tmp.n * 2) + r.y - 1
). Le rn
est juste de conserver les ordres de lignes par ID tout en facilitant la recherche de la ligne suivante - vous pouvez donc rechercher rn + 1
au lieu de trouver directement la prochaine valeur d'ID la plus élevée.
Il n'y a pas de différence de performances significative avec vos exemples de données, mais avec un millier de lignes ajoutées, la clause de modèle prend environ 5 secondes et le CTE récursif prend environ 1 seconde. avec un autre modèle de mille lignes prend environ 20 secondes et le CTE prend environ 3 secondes ; avec un autre millier de lignes, le modèle a pris environ 40 secondes et le CTE a pris environ 6 secondes ; et avec un autre millier de lignes (donc 4 008 au total), le modèle a pris environ 75 secondes et le CTE a pris environ 10 secondes. (Je me suis ennuyé en attendant la version modèle avec plus de lignes que cela ; je l'ai tué après cinq minutes avec 10 000). Je ne peux pas vraiment dire comment cela fonctionnera avec vos données réelles, mais sur cette base, cela vaut probablement la peine d'essayer.