以下代码创建一个包含几条记录的数据库,然后执行递归查询,然后使用UNION
运算符执行相同的递归查询。
如果我使用sqlite 3.8.3.1在Python 3.4.0上运行代码,则第一个递归查询会起作用,但第二个会失败。
如果我使用sqlite 3.8.4.3在SQLiteSpy内运行相同的代码,则两个查询都会成功。
如果我反转UNION
操作数的顺序(简单查询UNION
递归查询而不是递归查询UNION
简单查询),那么它在SQLiteSpy中也会失败。
在release notes of SQLite中,我没有找到任何会影响行为差异的内容。
如何让递归查询在Python中运行?
import sqlite3
db = sqlite3.connect(':memory:')
cur = db.cursor()
print('preparing stuff')
cur.executescript("""DROP TABLE IF EXISTS Parts;
CREATE TABLE Parts (
Id INTEGER PRIMARY KEY,
Desc TEXT,
ParentId INTEGER
);
INSERT INTO Parts VALUES (1, 'CEO', NULL);
INSERT INTO Parts VALUES (2, 'VIP Sales', 1);
INSERT INTO Parts VALUES (3, 'VIP Operations', 1);
INSERT INTO Parts VALUES (4, 'Sales Manager Europe', 2);
INSERT INTO Parts VALUES (5, 'Sales Manager USA', 2);
INSERT INTO Parts VALUES (6, 'Sales Rep Europe 1', 4);
INSERT INTO Parts VALUES (7, 'Sales Rep Europe 2', 4);
INSERT INTO Parts VALUES (8, 'Sales Rep USA 1', 5);
INSERT INTO Parts VALUES (9, 'Sales Rep USA 2', 5);""")
print('executing simple query')
cur.executescript("""WITH RECURSIVE Cte (
Level,
Id,
Desc,
ParentId,
ParentDesc
) AS (
SELECT 0,
Child.Id,
Child.Desc,
Parent.Id,
Parent.Desc
FROM Parts AS Child
JOIN Parts AS Parent ON Child.ParentId = Parent.Id
WHERE Child.Desc = 'Sales Rep USA 1'
UNION ALL
SELECT Cte.Level + 1,
Child.Id,
Child.Desc,
Parent.Id,
Parent.Desc
FROM Parts as Child, Cte
JOIN Parts AS Parent ON Child.ParentId = Parent.Id
WHERE Child.Id = Cte.ParentId
)
SELECT ParentId,
ParentDesc
FROM Cte;""")
print('executing query with union')
cur.executescript("""WITH RECURSIVE Cte (
Level,
Id,
Desc,
ParentId,
ParentDesc
) AS (
SELECT 0,
Child.Id,
Child.Desc,
Parent.Id,
Parent.Desc
FROM Parts AS Child
JOIN Parts AS Parent ON Child.ParentId = Parent.Id
WHERE Child.Desc = 'Sales Rep USA 1'
UNION ALL
SELECT Cte.Level + 1,
Child.Id,
Child.Desc,
Parent.Id,
Parent.Desc
FROM Parts as Child, Cte
JOIN Parts AS Parent ON Child.ParentId = Parent.Id
WHERE Child.Id = Cte.ParentId
)
SELECT ParentId,
ParentDesc
FROM Cte
UNION ALL
SELECT Id,
Desc
FROM Parts
WHERE Desc = 'Sales Rep USA 1';""")