Операторы цикла SQLite?
Есть ли какие-либо операторы цикла в SQLite, например FOR .. in .. LOOP
или что-то в этом роде? У меня есть два столбца StartRange, EndRange
, и мне нужно вставить целую последовательность в другую таблицу. Поэтому, если StartRange
равно 1 и EndRange
равно 3, необходимо сделать три вставки со значением, содержит 1, 2, 3
.
Ответы
Ответ 1
Вы можете делать такие вещи в прямом SQL, если у вас есть дополнительная таблица, которая содержит все целые числа, которые вам нужны.
Предположим, что ваш диапазон StartRange
и EndRange
находится в диапазоне от одного до десяти, и у вас есть таблица, подобная этой:
sqlite> select i from ints;
i
1
.
.
.
10
Эта таблица просто содержит все возможные целые числа, которые вам нужны (например, один-десять).
Тогда, если у вас также есть это:
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);
Вы можете сделать свои ВСТАВКИ в target
с соединением:
insert into target (i)
select ints.i
from ints join t on (ints.i >= t.startrange and ints.i <= t.endrange)
В результате получится следующее:
sqlite> select * from target;
i
1
2
3
Конечно, у вашего реального t
будет больше строк, поэтому вам нужно предложение WHERE, чтобы ограничить, какую строку t
вы смотрите.
Подобные вещи часто выполняются с датами (поиск "таблиц календаря" ).
Итак, если ваши диапазоны невелики (для некоторого определения small), тогда сгенерируйте таблицу ints
один раз, добавьте в нее индекс и используйте описанную выше методику, чтобы делать все INSERT прямо внутри базы данных. Другие базы данных имеют свои собственные способы (такие как PostgreSQL generate_series
), чтобы делать такие вещи без необходимости явной таблицы ints
, но SQLite (намеренно) ограничено.
SQL, как правило, основан на наборе, поэтому циклы не являются естественными. Естественно создавать соответствующие наборы, описывая, что вам нужно. OTOH, иногда неестественные действия необходимы и разумны.
Я не знаю, имеет ли это смысл для вашего приложения, я просто подумал, что продемонстрирую, как это можно сделать. Если этот подход не имеет смысла в вашем случае, вы можете сгенерировать кучу инструкций INSERT за пределами базы данных.
Ответ 2
Вы можете создавать циклы в SQL с рекурсивными триггерами. Использование mu - слишком короткая схема
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);
нам нужно включить рекурсивные триггеры в SQLite:
sqlite> PRAGMA recursive_triggers = on;
Сделайте временный триггер, чтобы выполнить цикл до конца диапазона:
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;
Отключить:
sqlite> insert into target values ((select t.startrange from t));
sqlite> select * from target;
3
2
1
sqlite>
Ответ 3
По-видимому, конструкция цикла в SQLite - это WITH RECURSIVE.
Эта ссылка на документацию содержит примерный код от десяти до десяти, набор плоттеров Мандельброта и решатель головоломки Sudoku, все в чистом SQL.
Здесь SQLite-запрос, который вычисляет последовательность Фибоначчи, дает вам ощущение:
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,...
И здесь Сито Эратосфена:
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;