我有一个简单的sqlite3表,如下所示:
Table: Part
Part SuperPart
wk0Z wk00
wk06 wk02
wk07 wk02
eZ01 eZ00
eZ02 eZ00
eZ03 eZ01
eZ04 eZ01
我需要运行一个递归查询来查找给定SuperPart及其所有子组的所有对。 所以我要说我有eZ00。 eZ00是eZ01的超级部件,eZ01是eZ03的超级部件。结果必须不仅包括对(eZ00,eZ01)和(eZ01和eZ03),还必须包括对(eZ00,eZ03)。
我知道还有其他方法来定义表格,但我在这里别无选择。 我知道如果我知道树的深度,我可以使用几个工会,但我不会总是知道我想去的深度。 它有助于拥有像WITH RECURSIVE这样的东西,甚至只有WITH(,,)AS x,但对于我搜索过的东西,这在sqlite中是不可能的,对吗?
有没有办法在sqlite3中执行此递归查询?
更新:
当提出这个问题时,SQLite不支持递归查询,但是as stated by @lunicon,SQLite现在支持递归CTE,因为3.8.3 sqlite.org/lang_with.html
答案 0 :(得分:30)
如果您有幸使用SQLite 3.8.3或更高版本,那么您可以使用WITH访问递归和非递归CTE:
感谢lunicon让我们了解此SQLite更新。
在3.8.3之前的 版本中,SQLite不支持递归CTE(或CTE),因此没有WITH in SQLite。由于你不知道它有多深,你不能使用标准的JOIN技巧伪造递归CTE。您必须以艰难的方式完成并在客户端代码中实现递归:
答案 1 :(得分:7)
在此SQLite Release 3.8.3 On 2014-02-03中增加了对CTE的支持。这是文档WITH clause 例如:
WITH RECURSIVE
cnt(x) AS (
SELECT 1
UNION ALL
SELECT x+1 FROM cnt
LIMIT 1000000
)
SELECT x FROM cnt;
答案 2 :(得分:4)
有一个黑客 http://dje.me/2011/03/26/sqlite-data-trees.html
-- A method for storing and retrieving hierarchical data in sqlite3
-- by using a trigger and a temporary table.
-- I needed this but had trouble finding information on it.
-- This is for sqlite3, it mostly won't work on anything else, however
-- most databases have better ways to do this anyway.
PRAGMA recursive_triggers = TRUE; -- This is not possible before 3.6.18
-- When creating the Node table either use a primary key or some other
-- identifier which the child node can reference.
CREATE TABLE Node (id INTEGER PRIMARY KEY, parent INTEGER,
label VARCHAR(16));
INSERT INTO Node (parent, label) VALUES(NULL, "root");
INSERT INTO Node (parent, label) VALUES(1, "a");
INSERT INTO Node (parent, label) VALUES(2, "b");
INSERT INTO Node (parent, label) VALUES(3, "c1");
INSERT INTO Node (parent, label) VALUES(3, "c2");
-- Create the temp table, note that node is not a primary key
-- which insures the order of the results when Node records are
-- inserted out of order
CREATE TEMP TABLE Path (node INTEGER, parent INTEGER,
label VARCHAR(16));
CREATE TRIGGER find_path AFTER INSERT ON Path BEGIN
INSERT INTO Path SELECT Node.* FROM Node WHERE
Node.id = new.parent;
END;
-- The flaw here is that label must be unique, so when creating
-- the table there must be a unique reference for selection
-- This insert sets off the trigger find_path
INSERT INTO Path SELECT * FROM Node WHERE label = "c2";
-- Return the hierarchy in order from "root" to "c2"
SELECT * FROM Path ORDER BY node ASC;
DROP TABLE Path; -- Important if you are staying connected
-- To test this run:
-- sqlite3 -init tree.sql tree.db
答案 3 :(得分:3)
根据sqlite with documentation中找到的样本,查询
DROP TABLE IF EXISTS parts;
CREATE TABLE parts (part, superpart);
INSERT INTO parts VALUES("wk0Z", "wk00");
INSERT INTO parts VALUES("wk06", "wk02");
INSERT INTO parts VALUES("wk07", "wk02");
INSERT INTO parts VALUES("eZ01", "eZ00");
INSERT INTO parts VALUES("eZ02", "eZ00");
INSERT INTO parts VALUES("eZ03", "eZ01");
INSERT INTO parts VALUES("eZ04", "eZ01");
WITH RECURSIVE
under_part(parent,part,level) AS (
VALUES('?', 'eZ00', 0)
UNION ALL
SELECT parts.superpart, parts.part, under_part.level+1
FROM parts, under_part
WHERE parts.superpart=under_part.part
)
SELECT SUBSTR('..........',1,level*3) || "(" || parent || ", " || part || ")" FROM under_part
;
会输出
(?, eZ00)
...(eZ00, eZ01)
...(eZ00, eZ02)
......(eZ01, eZ03)
......(eZ01, eZ04)
为“它应该”预期
递归表的初始记录可以替换为
VALUES ((SELECT superpart FROM parts WHERE part='eZ00'), 'eZ00', 0)
为了获得初始超级部分的父级,尽管在这种情况下根本没有父级。
答案 4 :(得分:2)
这是我能想到的最基本的查询,它会生成一个系列,我们从1,2开始并继续添加1直到我们达到20.没有太多用处但是玩一下这将有助于你建立更多复杂递归的
最基本的系列
WITH b(x,y) AS
(
SELECT 1,2
UNION ALL
SELECT x+ 1, y + 1
FROM b
WHERE x < 20
) SELECT * FROM b;
打印
1|2
2|3
3|4
4|5
5|6
6|7
7|8
8|9
9|10
10|11
11|12
12|13
13|14
14|15
15|16
16|17
17|18
18|19
19|20
20|21
这是另一个生成斐波纳契数的简单例子 我们从a = 0,b = 1开始,然后去a = b,b = a + b就像你在任何编程语言中那样做
斐波那契系列
WITH b(x,y) AS
(
SELECT 0,1
UNION ALL
SELECT y, x + y
FROM b
WHERE x < 10000
) select * FROM b;
打印
0|1
1|1
1|2
2|3
3|5
5|8
8|13
13|21
21|34
34|55
55|89
89|144
144|233
233|377
377|610
610|987
987|1597
1597|2584
2584|4181
4181|6765
6765|10946
10946|17711