我们有一个SQLite CTE UPDATE,它在3.18.0及更高版本中均可用,但在3.19.0中由于FOREIGN KEY约束而开始失败(错误19)。
以下是显示行为的示例玩具数据库。
sqlite> .version
SQLite 3.18.0 2017-03-28 18:48:43 424a0d380332858ee55bdebc4af3789f74e70a2b3ba1cf29d84b9b4bcf3e2e37
sqlite> .dump t2
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE T2 (Id INTEGER PRIMARY KEY AUTOINCREMENT , ParentId INTEGER NOT NULL , Name TEXT NOT NULL , FavoriteState INT NOT NULL DEFAULT 0, FOREIGN KEY (ParentId) REFERENCES T2(Id) );
INSERT INTO T2 VALUES(1,0,'/',2);
CREATE INDEX idx_pid_t2 ON T2 (ParentId);
CREATE INDEX idx_files_favstate_t2 on T2 (FavoriteState);
CREATE UNIQUE INDEX idx_pnc_t2 ON T2 (ParentId, Name);
COMMIT;
sqlite> PRAGMA foreign_keys=ON;
sqlite> WITH RECURSIVE under_favorite_path(parent) AS ( VALUES(1) UNION ALL SELECT T2.Id FROM T2 JOIN under_favorite_path ON T2.ParentId = under_favorite_path.parent ) UPDATE T2 SET FavoriteState = 1
WHERE Id IN under_favorite_path;
sqlite> select * from t2;
1|0|/|1
sqlite> WITH RECURSIVE under_favorite_path(parent) AS ( VALUES(1) UNION ALL SELECT T2.Id FROM T2 JOIN under_favorite_path ON T2.ParentId = under_favorite_path.parent ) UPDATE T2 SET FavoriteState = 2
WHERE Id IN under_favorite_path;
sqlite> select * from t2;
1|0|/|2
在3.19.0中禁用外键可以使UPDATE成功。
sqlite> .version
SQLite 3.19.0 2017-05-22 13:58:13 28a94eb282822cad1d1420f2dad6bf65e4b8b9062eda4a0b9ee8270b2c608e40
sqlite> .dump t2
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE T2 (Id INTEGER PRIMARY KEY AUTOINCREMENT , ParentId INTEGER NOT NULL , Name TEXT NOT NULL , FavoriteState INT NOT NULL DEFAULT 0, FOREIGN KEY (ParentId) REFERENCES T2(Id) );
INSERT INTO T2 VALUES(1,0,'/',2);
CREATE INDEX idx_pid_t2 ON T2 (ParentId);
CREATE INDEX idx_files_favstate_t2 on T2 (FavoriteState);
CREATE UNIQUE INDEX idx_pnc_t2 ON T2 (ParentId, Name);
COMMIT;
sqlite> PRAGMA foreign_keys=ON;
sqlite> WITH RECURSIVE under_favorite_path(parent) AS ( VALUES(1) UNION ALL SELECT T2.Id FROM T2 JOIN under_favorite_path ON T2.ParentId = under_favorite_path.parent ) UPDATE T2 SET FavoriteState = 1
WHERE Id IN under_favorite_path;
Error: FOREIGN KEY constraint failed
sqlite> PRAGMA foreign_keys=OFF;
sqlite> WITH RECURSIVE under_favorite_path(parent) AS ( VALUES(1) UNION ALL SELECT T2.Id FROM T2 JOIN under_favorite_path ON T2.ParentId = under_favorite_path.parent ) UPDATE T2 SET FavoriteState = 1
WHERE Id IN under_favorite_path;
sqlite> select * from t2;
1|0|/|1
这是我们的CTE的一个问题,该问题以前应该被标记吗?还是在更高版本的SQLite中可能已经退缩了?
最佳答案
问题不在于CTE,而是表包含无效数据(0
不是有效ID):
sqlite> pragma foreign_key_check; table rowid parent fkid ---------- ---------- ---------- ---------- T2 1 T2 0
When the row gets modified in any way, the constraint is checked:
sqlite> update t2 set name = name;
Error: FOREIGN KEY constraint failed
显然,当未修改FK列时,旧版本未检查约束。
关于sqlite - SQLite递归CTE UPDATE在3.18.0中运行,SQL_CONSTRAINT在3.19.0中运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46105601/