2011-09-10 10 views
15

Esiste qualche istruzione di loop in SQLite come FOR .. in .. LOOP o qualcosa del genere? Ho due colonne StartRange, EndRange e ho bisogno di inserire l'intera sequenza in un'altra tabella. Quindi se StartRange è 1 e EndRange è 3 è necessario creare tre inserti con valore, contiene 1, 2, 3.istruzioni loop SQLite?

+2

temo sarà necessario scrivere del codice imperativo fare esso, SQL è generalmente un linguaggio dichiarativo e solo le sue estensioni (come T-SQL, SQL/PL ecc.) supportano strutture di flusso di controllo come loop. Se dovrebbe essere facile, tuttavia, eseguire l'inserimento in una corsa utilizzando le transazioni SQLite. –

+0

Perl/Python/Ruby-script-to-the-rescue! :) –

+0

Questo dovrebbe essere spostato su dba.stackexchange.com? – anddam

risposta

8

È possibile eseguire questo tipo di operazione in SQL diretto se si dispone di una tabella aggiuntiva che contiene tutti gli interi necessari.

Supponiamo che il vostro StartRange e EndRange range compreso tra uno e dieci e si dispone di una tabella come questa:

sqlite> select i from ints; 
i 
1 
. 
. 
. 
10 

Questa tabella contiene semplicemente tutti i possibili numeri interi che è necessario (vale a dire da uno a dieci).

Poi, se hai anche questo:

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); 

Potete fare i vostri inserisce nella target con un join:

insert into target (i) 
select ints.i 
from ints join t on (ints.i >= t.startrange and ints.i <= t.endrange) 

Il risultato è questo:

sqlite> select * from target; 
i 
1 
2 
3 

Naturalmente il tuo vero t avrebbe più righe quindi vorresti una clausola WHERE per limitare quale riga di t si guarda.

Le cose simili vengono spesso eseguite con le date (cercare "tabelle del calendario").

Quindi, se gli intervalli sono di piccole dimensioni (per qualche definizione di piccolo) quindi generare il vostro tavolo ints una volta, aggiungere un indice ad esso, e utilizzare la tecnica di cui sopra per fare tutti gli inserti proprio all'interno del database. Altri database hanno i loro metodi (come PostgreSQL generate_series) per fare questo genere di cose senza bisogno di una tabella esplicita ints ma SQLite è (intenzionalmente) limitato.

SQL è generalmente basato su set, quindi i loop non sono naturali. Ciò che è naturale è costruire gli insiemi appropriati descrivendo ciò di cui hai bisogno. OTOH, a volte atti innaturali sono necessari e sensibili.

Non so se questo ha senso per la tua applicazione, ho solo pensato di dimostrare come si può fare. Se questo approccio non ha senso nel tuo caso, puoi generare una serie di istruzioni INSERT al di fuori del database.

+0

Le tabelle SQLite hanno numeri di riga che possono essere utilizzati nelle query. – reinierpost

+0

@reinierpost Ti stai riferendo a 'rowid'? –

+0

Sì. (e con il tuo nome, è * ancora * troppo breve) – reinierpost

14

È possibile creare loop in SQL con trigger ricorsivi.Utilizzando mu è troppo breve 's schema

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); 

abbiamo bisogno di abilitare i trigger ricorsivi in ​​SQLite:

sqlite> PRAGMA recursive_triggers = on; 

Fai un trigger temporaneo per ciclo fino alla fine del campo:

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; 

calci fuori:

sqlite> insert into target values ((select t.startrange from t)); 
sqlite> select * from target; 
3 
2 
1 
sqlite> 
+2

Ecco la magia nera di cui avevo bisogno. Grazie compagno! –

2

Apparentemente il costrutto di ciclo in SQLite è la clausola WITH RECURSIVE. Questo link alla documentazione include un codice di esempio da dieci a dieci, un plotter di set di Mandelbrot e un risolutore di puzzle di Sudoku, tutto in puro SQL. Ecco una query SQLite che calcola la sequenza di Fibonacci per darvi una sensazione di esso:

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,... 

Ed ecco un Sieve of Eratosthenes:

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; 
Problemi correlati