Следующий

Как работает рекурсия? Иерархические / рекурсивные SQL запросы в базах данных SQLite: WITH RECURSIVE

24 Просмотры· 06/18/20
Кирилл Антонов
Кирилл Антонов
Подписчики
0

Помощь проекту:
WMR: R288272666982
WMZ: Z293550531456
Яндекс.Деньги: 410011531129223

Рубрика SQLite на сайте: http://zametkinapolyah.ru/zametki-o-mysql/sqlite/
Паблик блога в ВК: https://vk.com/zametkinapolyah
Тематическая группа в ВК: https://vk.com/zametki_bd


-- Рекурсивные/иерархические SQL запросы в базах данных SQLite:
-- WITH RECURSIVE clause.

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

Здесь мы попробуем разобраться и с рекурсией и с
иерархическими SQL-запросами. SQLite, как и многие другие
СУБД - реляционная: база данных состоит из таблиц, таблицы
в свою очередь состоят из строк и столбцов, другими словами:
данные представлены двумерно.

В нашей жизни, так уж получается, что не все объекты удобно
описывать двумерной моделью: крупная международная компания
с холдингами и филиалами в различных странах, файловая система
компьютера, карьерная лестница в компании - эти данные намного
удобнее описывать иерархической моделью.

Конечно, например, структуру крупной компании можно описать
несколькими таблицами, например, таблицы стран: Китай, Россия,
США, Англия, Япония. Далее спуститься на уровень ниже
и создать таблицы регионов для страны: Москва, Иваново,
Новосибирск, Омск. Но такой подход не всегда удобен, поскольку
не всегда известна глубина вложенности.

В 1999 году международное сообщество решило эту проблему
путем добавления в стандарт (SQL-1999) рекурсивных SQL-запросов,
хотя компания Oracle это сделала немного раньше (и по Ораклу
рекурсивные запросы называются иерархическими).


*/

http://sqlite.org/lang_with.html


/*
Общий синтаксис рекурсивных запросов в SQLite выглядит следующим
образом:

WITH [RECURSIVE] cte-table-name AS (select-stmt);

Но это не всё, рекурсивный SQL запрос состоит из двух запросов SELECT,
если эта фраза в данном случае уместна:

WITH RECURSIVE
cte-table-name AS (initial-select UNION [ALL] recursive-select)
cte-select;


2 1 cte-table-name 1 2

initial-select (не должен в себя включать ORDER BY, LIMIT, OFFSET) -
точка, откуда начинается рекурсия.

recursive-select - рекурсивный запрос, который будет вполняться
до тех пор, пока условие не будет выполнено, два верхних запроса
позволяют создать наполнить нашу импровизированную таблицу данными
cte-select - позволяет работать с данными таблицы

1-1000

WITH RECURSIVE
table1(col1) AS (
VALUES(1)
UNION ALL
SELECT col1+1 FROM table1
WHERE col1(знак меньше)1000)
SELECT col1 FROM table1;

WITH RECURSIVE
table1(col1) AS (
SELECT 1
UNION ALL
SELECT col1+1 FROM table1
LIMIT 1000
)
SELECT col1 FROM table1;
table1
col1
2

3 2 1 table1 1 2 3

-- Создадим таблицу
CREATE TABLE org(
name TEXT PRIMARY KEY,
boss TEXT REFERENCES org
);

-- наполним ее данными
INSERT INTO org VALUES('Alice',NULL);
INSERT INTO org VALUES('Bob','Alice');
INSERT INTO org VALUES('Cindy','Alice');
INSERT INTO org VALUES('Dave','Bob');
INSERT INTO org VALUES('Emma','Bob');
INSERT INTO org VALUES('Fred','Cindy');
INSERT INTO org VALUES('Gail','Cindy');

SELECT * FROM org;


-- Для лучшего понимания работы рекурсии и поиска значений
-- рекомендую вам погуглить:
-- FIFO, поиск в глубину и поиск в ширину


0|Alice
1|Bob
1|Cindy
2|Dave
2|Emma
2|Fred
2|Gail

-- поиск в глубину
WITH RECURSIVE
under_alice(name,level) AS (
VALUES('Alice',0)
UNION ALL
SELECT org.name, under_alice.level+1
FROM org JOIN under_alice ON org.boss=under_alice.name
ORDER BY 2 DESC
)
SELECT level, name FROM under_alice;


Alice
...Bob
...Cindy
......Dave
......Emma
......Fred
......Gail

WITH RECURSIVE
under_alice(name,level) AS (
VALUES('Alice',0)
UNION ALL
SELECT org.name, under_alice.level+1
FROM org JOIN under_alice ON org.boss=under_alice.name
ORDER BY 2 DESC
)
SELECT substr('..........',1,level*3) || name FROM under_alice;

Показать больше

 0 Комментарии sort   Сортировать


Следующий