我们有一个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版本中退化?
答案 0 :(得分:1)
问题不在于CTE,而是表包含无效数据(0
不是有效ID):
sqlite> pragma foreign_key_check; table rowid parent fkid ---------- ---------- ---------- ---------- T2 1 T2 0
当以任何方式修改行时,将检查约束:
sqlite> update t2 set name = name;
Error: FOREIGN KEY constraint failed
显然,旧版本没有在未修改FK列时检查约束。