web-dev-qa-db-fra.com

Instructions de boucle SQLite?

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.

22
kseen

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.

11
mu is too short

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> 
20
Doug Currie

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;
10
rob