Czy są jakieś instrukcje pętli w SQLite, takie jak FOR .. in .. LOOP
czy coś w tym stylu? Mam dwie kolumny StartRange, EndRange
i muszę wstawić całą sekwencję w innej tabeli. Więc jeśli StartRange
wynosi 1 i EndRange
jest 3, konieczne jest utworzenie trzech wstawek o wartości zawierającej 1, 2, 3
.Instrukcje pętli SQLite?
Odpowiedz
Możesz zrobić tego rodzaju rzeczy w prostym SQL, jeśli masz dodatkową tabelę zawierającą wszystkie liczby całkowite, których potrzebujesz.
Załóżmy swoją StartRange
i EndRange
zakres od jednego do dziesięciu i masz tabelę tak:
sqlite> select i from ints;
i
1
.
.
.
10
Tabela ta zawiera po prostu wszystkich możliwych liczb całkowitych, które trzeba (to znaczy jeden do dziesięciu).
Następnie, jeśli masz również to:
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);
można zrobić wkładek do target
z złączenia:
insert into target (i)
select ints.i
from ints join t on (ints.i >= t.startrange and ints.i <= t.endrange)
Rezultat jest taki:
sqlite> select * from target;
i
1
2
3
Oczywiście Twój prawdziwy t
miałby więcej wierszy, więc potrzebujesz klauzuli WHERE do ograniczenia tego wiersza z t
, którego szukasz.
Podobne rzeczy często robimy z datami (spójrz na "tabele kalendarza").
Więc jeśli zakresy są małe (dla niektórych definicji małej), a następnie wygenerować tabelę ints
raz, dodać indeks do niego i użyj powyższej techniki zrobić wszystkie wkładek bezpośrednio w bazie danych. Inne bazy danych mają własne sposoby (takie jak PostgreSQL's generate_series
) do robienia tego typu rzeczy bez potrzeby wyraźnej tabeli ints
, ale SQLite jest (celowo) ograniczony.
SQL jest ogólnie oparty na ustawieniach, więc pętle nie są naturalne. To, co naturalne, to budowanie odpowiednich zestawów poprzez opisywanie tego, czego potrzebujesz. OTOH, czasami nienaturalne działania są konieczne i rozsądne.
Nie wiem, czy to ma sens dla twojej aplikacji, po prostu pomyślałem, że pokażę, jak można to zrobić. Jeśli takie podejście nie ma sensu w twoim przypadku, możesz wygenerować kilka instrukcji INSERT poza bazą danych.
Tabele SQLite mają numery wierszy, które mogą być używane w zapytaniach. – reinierpost
@reinierpost Czy odnosisz się do 'rowid'? –
Tak. (i z twoim imieniem, to jest * nadal * za krótko) – reinierpost
Możesz tworzyć pętle w SQL z rekurencyjnymi wyzwalaczami.Korzystanie mu jest zbyt krótki „s schematu
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);
musimy umożliwić rekurencyjnych wyzwalaczy w SQLite:
sqlite> PRAGMA recursive_triggers = on;
Zrób tymczasowe spust do pętli aż do końca zakresu:
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;
kick it off:
sqlite> insert into target values ((select t.startrange from t));
sqlite> select * from target;
3
2
1
sqlite>
Oto czarna magia, której potrzebowałem. Dzięki stary! –
Najwyraźniej konstruktem pętli w SQLite jest klauzula WITH RECURSIVE. Ten odnośnik do dokumentacji zawiera przykładowy kod od liczby dziesiętnej do dziesięciu, ploter z zestawu Mandelbrota i narzędzie do rozwiązywania zagadek sudoku, wszystkie w czystym SQL. Oto kwerendy SQLite, który oblicza ciągu Fibonacciego, aby dać Ci poczuć do niego:
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,...
A oto 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;
obawiam musisz napisać jakiś imperatyw kod do zrobienia to, SQL jest ogólnie językiem deklaratywnym i tylko jego rozszerzenia (takie jak T-SQL, SQL/PL itp.) wspierają struktur kontroli przepływu, takich jak pętle. Jeśli jednak powinno być łatwe, należy wykonać wstawianie w jednym przebiegu za pomocą transakcji SQLite. –
Perl/Python/Ruby-script-to-the-rescue! :) –
Czy należy to przenieść na dba.stackexchange.com? – anddam