Операторы цикла SQLite? - PullRequest
       20

Операторы цикла SQLite?

20 голосов
/ 10 сентября 2011

Есть ли в SQLite операторы цикла вроде FOR .. in .. LOOP или что-то в этом роде?У меня есть два столбца StartRange, EndRange, и мне нужно вставить всю последовательность в другой таблице.Поэтому, если StartRange равно 1, а EndRange равно 3, необходимо сделать три вставки со значением, содержащим 1, 2, 3.

Ответы [ 3 ]

18 голосов
/ 10 сентября 2011

Вы можете создавать циклы в 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> 
10 голосов
/ 10 сентября 2011

Вы можете делать такие вещи в прямом 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 прямо внутри база данных. Другие базы данных имеют свои собственные способы (такие как generate_series) в PostgreSQL, чтобы делать подобные вещи без явной таблицы ints, но SQLite (намеренно) ограничен.

SQL обычно основан на множествах, поэтому циклы не являются естественными. Естественно строить соответствующие наборы, описывая то, что вам нужно. OTOH, иногда неестественные действия необходимы и разумны.

Я не знаю, имеет ли это смысл для вашего приложения, я просто подумал, что продемонстрирую, как это можно сделать. Если этот подход не имеет смысла в вашем случае, вы можете сгенерировать кучу операторов INSERT вне базы данных.

6 голосов
/ 08 августа 2016

Очевидно, что циклическая конструкция в SQLite является предложением WITH RECURSIVE . Эта ссылка на документацию содержит пример кода с количеством до десяти, наборный плоттер Мандельброта и решатель головоломок Судоку, все на чистом 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...