问题描述
例如,假设 DB 有外键 A.b_id -> B.id,删除时带有 SET NULL。 如果某个 B.id 的记录被删除,所有 b_id 引用将被设置为 NULL。
但是如果 A 已经包含 A.b_id 具有不在 B.id 中的值的记录(它是在没有外键支持的情况下插入的),有没有办法强制 sqlite DB 检查外键并将此类数据设置为 NULL?
在启动应用程序时检查内部数据库(资源)的版本是否高于用户数据库。 如果是这样,它备份用户数据库,将内部空数据库复制到用户存储。然后关闭外键支持并用备份中的数据填充新数据库,自动为所有具有相同名称的列逐表插入循环表。重新开启外键支持。
一切正常,但如果旧数据库的某个表中没有外键约束,而新数据库有外键约束,则数据将按原样插入并且链接无法指向任何地方(可能错误链接是不可避免的并且不相关提问)。
是的,我了解一种在不关闭外键支持的情况下插入的方法,但它需要了解我想避免的表依赖顺序。
提前感谢您的帮助!
解决方法
虽然我不知道有什么方法可以自动将表中一列的所有孤立值设置为 NULL
(应该)引用另一个表中的另一列,但有一种方法可以获取报告所有这些情况,然后采取相应的行动。
这是 PRAGMA
语句 foreign_key_check
:
PRAGMA schema.foreign_key_check;
或单表检查:
PRAGMA schema.foreign_key_check(table-name);
来自文档:
foreign_key_check pragma 检查数据库,或调用的表 “表名”,用于违反的外键约束。这 foreign_key_check pragma 为每个外键返回一行输出 违反。每个结果行中有四列。第一列 是包含 REFERENCES 子句的表的名称。这 第二列是包含无效行的 rowid REFERENCES 子句,如果子表是 WITHOUT ROWID,则为 NULL 桌子。第三列是所引用的表的名称。 第四列是具体外键约束的索引 那失败了。 foreign_key_check 输出中的第四列 pragma 是与输出中的第一列相同的整数 foreign_key_list 编译指示。当指定了“表名”时,唯一的 检查的外键约束是那些由 REFERENCES 创建的 表名的 CREATE TABLE 语句中的子句。
检查使用此 PRAGMA
语句或其对应函数 pragma_foreign_key_check()
的方法的简化 demo。
您可以获得每个表中所有有问题的行的 rowid
列表。
在您的情况下,您可以执行一个 UPDATE
语句,该语句将设置为 NULL
所有孤立的 b_id
:
UPDATE A
SET b_id = NULL
WHERE rowid IN (SELECT rowid FROM pragma_foreign_key_check() WHERE "table" = 'A')
这也适用于更高版本的 SQLite:
UPDATE A
SET b_id = NULL
WHERE rowid IN (SELECT rowid FROM pragma_foreign_key_check('A'))
但它似乎不适用于 SQLite 3.27.0