默认情况下,SQLite 真的不保留外键约束的数据完整性吗?

Does SQLite really not preserve data integrity of foreign key constraints by default?

较新版本的 SQLite 支持外键约束。可以定义

1
2
3
CREATE TABLE MASTER (_ID INTEGER PRIMARY KEY, ...);
CREATE TABLE SERVANT (_ID INTEGER PRIMARY KEY, MASTERID INTEGER,
  FOREIGN KEY(MASTERID) REFERENCES MASTER(_ID);

根据文档,默认情况下"NO ACTION" 用于ON DELETE 和ON UPDATE。但与其他星展银行相反,"NO ACTION"似乎并不意味着不执行删除或更新。这似乎意味着没有采取任何措施来保持完整性,至少根据我的测试(*)并且如果我理解文档正确:

Configuring"NO ACTION" means just that: when a parent key is modified
or deleted from the database, no special action is taken.

因此

1
2
3
INSERT INTO MASTER (_ID) VALUES (1);
INSERT INTO SERVANT (_ID, MASTERID) VALUES (1,1);
DELETE FROM MASTER;

给我一个空的 MASTER 表和一个 SERVANT 表,外键指向任何地方。

任何人都可以确认这种行为并解释为什么以这种方式实施吗?还是我必须配置一些东西才能使外键支持工作?
我是 SQLite 开发的新手,如果这是一个愚蠢的问题,请原谅我。

编辑:(*) 我的测试有缺陷,请参阅下面的答案。


我会尽量自己回答:

不,如果配置正确,SQLite 在这种情况下会保持数据完整性。默认情况下使用"NO ACTION",如果引用表中仍有引用键(用 3.7.x 测试),则禁止删除或更新主键。
我的错是我不知道必须为每个与数据库的新连接配置 PRAGMA foreign_keys = ON;

编辑:我认为 SQLite 文档在这里具有误导性。


你是对的。 "NO ACTION" 意味着没有做任何事情来保持外键约束的完整性。有关可以设置的选项的详细信息,请参阅文档。

在这种情况下,您还可以设置 4 个其他选项。 RESTRICT、SET NULL、SET DEFAULT 和 CASCADE。简要说明他们的工作:

RESTRICT - MASTER 表中的行只有在 SERVANT 表中的任何行都没有引用时才能被删除。

SET NULL - 删除 MASTER 表中的一行将导致 SERVANT 表中的任何 FK 设置为 NULL。

SET DEFAULT - 与设置 NULL 类似,只是 FK 设置为默认值而不是 NULL。

CASCADE - 删除 MASTER 表中的行将导致 SERVANT 表中引用已删除 MASTER 行的所有行也被删除。

要更改这些选项,您必须修改您的创建语句以指定更新和删除操作。

1
2
3
4
5
6
7
8
9
CREATE TABLE MASTER (
  _ID INTEGER PRIMARY KEY,
  ...
);
CREATE TABLE SERVANT (
  _ID INTEGER PRIMARY KEY,
  MASTERID INTEGER,
  FOREIGN KEY(MASTERID) REFERENCES MASTER(_ID) ON UPDATE CASCADE ON DELETE SET NULL
);

编辑:
不要忘记确保您的 SQLite 版本是使用外键支持编译的,并且您已通过指定 PRAGMA foreign_keys = ON;

启用它