Операторы цикла 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;