Existe-t-il des instructions de boucle dans SQLite comme FOR .. in .. LOOP
ou quelque chose comme ça? J'ai deux colonnes StartRange, EndRange
et je dois insérer toute la séquence dans un autre tableau. Donc si StartRange
est 1 et EndRange
est 3, il est nécessaire de faire trois insertions avec valeur, contient 1, 2, 3
.
Vous pouvez faire ce genre de chose en SQL simple si vous avez une table supplémentaire qui contient tous les entiers dont vous avez besoin.
Supposons que votre StartRange
et EndRange
se situent entre un et dix et que vous ayez un tableau comme celui-ci:
sqlite> select i from ints;
i
1
.
.
.
10
Ce tableau contient simplement tous les entiers possibles dont vous avez besoin (c'est-à-dire un à dix).
Alors si vous avez aussi ceci:
sqlite> create table t (startrange int not null, endrange int not null);
sqlite> insert into t values(1, 3);
sqlite> create table target (i int not null);
Vous pouvez faire vos INSERTs dans target
avec une jointure:
insert into target (i)
select ints.i
from ints join t on (ints.i >= t.startrange and ints.i <= t.endrange)
Le résultat est le suivant:
sqlite> select * from target;
i
1
2
3
Bien sûr, votre vrai t
aurait plus de lignes, vous voudriez donc une clause WHERE pour limiter la ligne de t
que vous regardez.
Des choses similaires se font souvent avec les dates (recherchez les "tableaux de calendrier").
Donc, si vos plages sont petites (pour une définition de petite ), générez votre table ints
une fois, ajoutez-y un index et utilisez la technique ci-dessus pour faire tous les INSERTs directement dans la base de données. D'autres bases de données ont leurs propres méthodes (comme celles de PostgreSQL generate_series
) pour faire ce genre de chose sans avoir besoin d'une table explicite ints
mais SQLite est (intentionnellement) limité.
SQL est généralement basé sur un ensemble, les boucles ne sont donc pas naturelles. Ce qui est naturel, c'est de créer les ensembles appropriés en décrivant ce dont vous avez besoin. OTOH, des actes parfois contre nature sont nécessaires et sensés.
Je ne sais pas si cela a du sens pour votre application, je pensais simplement démontrer comment cela peut être fait. Si cette approche n'a pas de sens dans votre cas, vous pouvez générer un groupe d'instructions INSERT en dehors de la base de données.
Vous pouvez faire des boucles en SQL avec des déclencheurs récursifs. Utilisation de mu est trop court schéma
sqlite> create table t (startrange int not null, endrange int not null);
sqlite> insert into t values(1, 3);
sqlite> create table target (i int not null);
nous devons activer les déclencheurs récursifs dans SQLite:
sqlite> PRAGMA recursive_triggers = on;
Effectuez un déclenchement temporaire pour boucler jusqu'à la fin de la plage:
sqlite> create temp trigger ttrig
...> before insert on target
...> when new.i < (select t.endrange from t) begin
...> insert into target values (new.i + 1);
...> end;
Coup d'envoi:
sqlite> insert into target values ((select t.startrange from t));
sqlite> select * from target;
3
2
1
sqlite>
Apparemment, la construction en boucle dans SQLite est la clause WITH RECURSIVE . Ce lien de documentation contient un exemple de code de comptage jusqu'à dix, un traceur de jeu Mandelbrot et un résolveur de casse-tête Sudoku, le tout en SQL pur. Voici une requête SQLite qui calcule la séquence de Fibonacci pour vous en donner une idée:
sqlite> WITH RECURSIVE
...> fibo (curr, next)
...> AS
...> ( SELECT 1,1
...> UNION ALL
...> SELECT next, curr+next FROM fibo
...> LIMIT 100 )
...> SELECT group_concat(curr) FROM fibo;
1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,...
Et voici un Tamis d'Eratosthène :
begin transaction;
drop table if exists naturals;
create table naturals
( n integer unique primary key asc,
isprime bool,
factor integer);
with recursive
nn (n)
as (
select 2
union all
select n+1 as newn from nn
where newn < 1e4
)
insert into naturals
select n, 1, null from nn;
insert or replace into naturals
with recursive
product (prime,composite)
as (
select n, n*n as sqr
from naturals
where sqr <= (select max(n) from naturals)
union all
select prime, composite+prime as prod
from
product
where
prod <= (select max(n) from naturals)
)
select n, 0, prime
from product join naturals
on (product.composite = naturals.n)
;
commit;