小。速度很快。可靠。
选择任意三个。
SQLite外键支持

概述

本文档描述了对SQL外键约束的支持引入SQLite版本3.6.19(2009-10-14).

第一部分介绍了SQL外键的概念,并定义术语用于文档的其余部分。第2节描述了步骤应用程序必须采用才能在中启用外键约束SQLite(默认情况下禁用)。下一节,第3节,描述用户必须创建才能使用的索引外键约束,以及为了有效运行的外键约束。第4节描述SQLite和第5节描述了交流发电机DROP表格命令是增强以支持外键约束。最后,第6节列举当前实现缺少的功能和限制。

本文档未包含所用语法的完整描述在SQLite中创建外键约束。这可以发现为文档的一部分创建表格声明。

1外键约束简介

SQL外键约束用于强制“存在”关系表之间。例如,考虑使用以下SQL命令:

CREATE TABLE艺术家(artistid INTEGER主键,艺人姓名文本);CREATE TABLE曲目(trackid整数,轨道名称文本,轨道艺术家INTEGER--必须映射到artist.artistid!);

使用此数据库的应用程序有权假定中的每一行轨道表中存在对应的行艺术家表。毕竟,声明中的评论是这样说的。不幸的是,如果用户使用外部工具或如果应用程序中存在错误,则可能会将行插入轨道不对应于艺术家表。或者可以从中删除行艺术家桌子,离开中的孤立行轨道与任何中的其余行艺术家。这可能会导致应用程序或应用程序稍后发生故障,或至少使编码应用更加困难。

一种解决方案是向数据库添加SQL外键约束模式以强制执行艺术家轨道表。为此,可以添加外键定义通过修改轨道下表:

CREATE TABLE曲目(trackid整数,轨道名称文本,轨道艺术家INTEGER,外键(trackartist)参考艺术家(artistid));

这样,约束由SQLite强制执行。正在尝试插入划入轨道与任何中的行艺术家表将失败,尝试也将失败从中删除行艺术家存在依赖项时的表中的行轨道表有一个例外:如果中的键列轨道表为NULL,则没有相应的中的条目艺术家表是必需的。用SQL表示,这意味着对于轨道表,如下表达式的计算结果为true:

trackartist为空或存在(从artist中选择1,其中artisti=trackartest)

提示:如果应用程序需要更严格的艺术家轨道,其中不允许NULL值在中轨道艺术家列,只需添加适当的模式的“NOT NULL”约束。

有几种其他方法可以添加等效的外键声明创建表格声明。请参阅CREATE TABLE文档了解详细信息。

下面的SQLite命令行会话说明了添加到轨道表:

sqlite>SELECT*FROM艺术家;艺人艺名--------  -----------------1迪安·马丁2弗兰克·辛纳特拉sqlite>SELECT*FROM轨迹;trackid trackname轨迹艺术家-------  -----------------  -----------11这是阿莫尔112圣诞布鲁斯113我的方式2方形>--这将失败,因为插入trackartist列(3)的值方形>--与艺术家表中的行不对应。sqlite>插入轨道值(14,“Bojangles先生”,3);SQL错误:外键约束失败方形>--这之所以成功,是因为向trackartist中插入了NULL。A类方形>--在这种情况下,不需要artist表中的相应行。sqlite>INSERT INTO track VALUES(14,'Mr.Bojangles',NULL);方形>--尝试修改记录的trackartist字段方形>--been inserted也不起作用,因为trackartist(3)的新值方形>--仍然不对应于艺术家表中的任何行。sqlite>UPDATE track SET trackartist=3 WHERE trackname='Mr.Bojangles';SQL错误:外键约束失败方形>--将所需行插入艺术家表。这样就可以方形>--更新插入的行以将trackartist设置为3(因为相应的方形>--艺术家表中的行现在存在)。sqlite>插入艺术家价值观(3,‘小萨米·戴维斯’);sqlite>UPDATE track SET trackartist=3 WHERE trackname='Mr.Bojangles';方形>--现在,“Sammy Davis Jr.”(artistid=3)已添加到数据库中,方形>--可以使用此艺术家插入新曲目,而不会违反sqlite公司>--外键约束:sqlite>插入曲目值(15,“Boogie Woogie”,3);

正如您所期望的那样,不可能将数据库操作到某个状态通过删除或更新艺术家表或:

方形>--尝试删除“Frank Sinatra”的艺术家记录失败,因为方形>--跟踪表包含引用它的行。sqlite>从艺术家删除WHERE artistname='Frank Sinatra';SQL错误:外键约束失败方形>--删除曲目表中指向艺术家的所有记录方形>--“弗兰克·辛纳屈”。只有这样才能删除艺术家。sqlite>DELETE FROM track WHERE trackname='My Way';sqlite>从艺术家删除WHERE artistname='Frank Sinatra';方形>--尝试在artist表中更新行的artistid方形>--跟踪表中存在引用它的记录。sqlite>UPDATE artist SET artistid=4 WHERE artistname='Dean Martin';SQL错误:外键约束失败方形>--一旦所有引用艺术家表中某行的记录都有方形>--删除后,可以修改行的artistid。sqlite>DELETE FROM track WHERE trackname IN('That’s Amore','Christmas Blues');sqlite>UPDATE artist SET artistid=4 WHERE artistname='Dean Martin';

SQLite使用以下术语:

如果子表中的每一行都满足外键约束一个或多个子键列为NULL,或者存在父表中每个父键列都包含值的行等于其关联子键列中的值。

在上段中,当值为使用规则进行比较明确规定在这里以下澄清适用:

2启用外键支持

为了在SQLite中使用外键约束,库必须编译时两者都不使用SQLITE_OMIT_foregin_KEY(SQLITE_OMIT_foregin_KEY)也不是SQLITE_OMIT_TRIGGER公司定义。如果定义了SQLITE_OMIT_TRIGGER但SQLITE_OMIT_FOREIGN_KEY不是,那么SQLITE的行为与以前一样版本3.6.19(2009-10-14)-外键定义被解析,可能是使用查询PRAGMA外语_密钥_列表,但外键约束没有强制执行。这个PRAGMA外文_键命令在此中是no-op配置。如果定义了OMIT_FOREIGN_KEY,则外键甚至无法解析定义(试图指定外部键定义是一个语法错误)。

假设在启用了外键约束的情况下编译库,它仍然必须由应用程序在运行时使用PRAGMA外文_键命令。例如:

sqlite>PRAGMA foreign_keys=ON;

默认情况下禁用外键约束(用于向后兼容),因此必须分别为每个数据库连接.(但请注意,SQLite的未来版本可能会发生变化因此,默认情况下启用外键约束。小心开发人员不会对是否启用外键进行任何假设默认设置,但将根据需要启用或禁用它们。)应用程序还可以使用PRAGMA外文_键对的声明确定当前是否启用了外键。以下内容命令行会话演示了这一点:

sqlite>PRAGMA foreign_keys;0sqlite>PRAGMA foreign_keys=ON;sqlite>PRAGMA foreign_keys;1sqlite>PRAGMA foreign_keys=关闭;sqlite>PRAGMA foreign_keys;0

提示:如果命令“PRAGMA foreign_keys”没有返回任何数据,而是返回包含“0”或“1”的单行,然后是您所在的SQLite版本using不支持外键(可能是因为它早于3.6.19或因为它是用编译的SQLITE_OMIT_FOREIGN_KEY数据库SQLITE_OMIT_TRIGGER公司定义)。

无法启用或禁用外键约束在中间多阶段交易(当SQLite不在中自动提交模式). 尝试这样做不会返回错误;它根本没有效果。

三。必需和建议的数据库索引

通常,外键约束的父键是的主键父表。如果它们不是主键,则父键列必须共同受UNIQUE约束或具有a唯一索引。如果父键列具有UNIQUE索引,则该索引必须使用指定的排序规则序列在父表的CREATE TABLE语句中。例如,

CREATE TABLE父项(一个主键,b UNIQUE,c,d,e,f);在父项(c,d)上创建唯一索引i1;在父项(e)上创建索引i2;在父级上创建唯一索引i3(f COLLATE nocase);CREATE TABLE child1(f,g REFERENCES parent(a));--好的创建表child2(h,i引用父项(b));--好的创建表child3(j,k,外键(j,k)引用父项(c,d));--好的CREATE TABLE child4(l,m REFERENCES parent(e));--错误!CREATE TABLE child5(n,o REFERENCES父级(f));--错误!创建表child6(p,q,外键(p,q)引用父项(b,c));--错误!CREATE TABLE child7(r REFERENCES parent(c));--错误!

作为表的一部分创建的外键约束孩子1,孩子2孩子3都很好。外键声明为表的一部分孩子4是一个错误,因为即使父键列被索引,索引不是UNIQUE。表的外键孩子5是一个错误,因为即使父键列具有唯一的索引时,索引使用不同的排序序列。桌子孩子6孩子7不正确,因为while它们的父键上都有UNIQUE索引,这些键不是与单个UNIQUE索引的列完全匹配。

如果数据库架构包含需要查找的外键错误如果要识别多个表定义,则这些错误不是创建表时检测到。相反,这些错误会阻止应用程序准备修改内容的SQL语句以使用外键的方式创建子表或父表。更改内容时报告的错误是“DML错误”和错误架构更改时报告的是“DDL错误”。换句话说,错误配置的外键约束要求查看子级和父级都是DML错误。外键DML错误的英语错误消息通常是“外键不匹配”,但如果父项表不存在。如果出现以下情况,则会报告外键DML错误:

上面的最后一个项目符号如下所示:

创建表parent2(a,b,主键(a,b));CREATE TABLE child8(x,y,FOREIGN KEY(x,y)REFERENCES parent2);--好的CREATE TABLE child9(x REFERENCES parent2);--错误!CREATE TABLE child10(x,y,z,外键(x,y,z)引用parent2);--错误!

相比之下,如果仅通过查找即可识别外键错误在子表的定义中,不必查询父表定义,然后创建表格子表的语句失败。因为错误在架构更改期间发生,这是DDL错误。无论何种情况,都会报告外键DDL错误表已创建。

子键列不需要索引,但它们几乎总是有益的。返回中的示例第1部分,每次应用程序艺术家表(父表),它执行与以下SELECT语句等效的搜索用于引用中的行轨道表(子表)。

从track中选择rowid WHERE trackartist=?

在哪里?中的替换为艺术家要从中删除的记录的列艺术家表格(召回那个轨道艺术家列是子键艺术家列是父键)。或者,更一般地说:

从<child-table>WHERE<child-key>=:parent_key_value选择行ID

如果此SELECT返回任何行,则SQLite得出以下结论从父表中删除行将违反外键约束并返回错误。如果父键的内容修改或将新行插入父表。如果这些查询不能使用索引,则必须执行对整个子表进行线性扫描。在非普通数据库中,这可能昂贵得令人望而却步。

因此,在大多数实际系统中,应该在子键列上创建索引每个外键约束的。子键索引没有成为(通常不会成为)唯一索引。再次回到第1节中的示例高效实现外键的完整数据库模式约束可能是:

CREATE TABLE艺术家(artistid INTEGER主键,艺人姓名文本);CREATE TABLE曲目(trackid整数,轨道名称文本,trackartist INTEGER参考艺术家);CREATE INDEX trackindex ON track(轨迹艺术家);

上面的块使用速记形式创建外键约束。附上“参考<父表>“子句到列定义创建一个外键约束,该约束将列映射到的主键<父表>。请参阅创建表格有关更多详细信息的文档。

4高级外键约束功能

4.1.复合外键约束

复合外键约束是子键和父键都是复合键。例如,考虑以下数据库架构:

CREATE TABLE相册(白蛋白艺术家TEXT,albumname文本,二元albumcover,主键(albumartist,albumname));CREATE TABLE歌曲(songid整数,歌曲艺术家文本,歌曲集文本,歌曲名文本,外键(歌曲艺术家,歌曲专辑)参考专辑(专辑艺术家,专辑名称));

在这个系统中,歌曲表中的每个条目都需要映射到一个条目在相册表中使用相同的艺术家和相册组合。

父键和子键必须具有相同的基数。在SQLite中,如果有任何子键列(在本例中为songartist和songabum)为NULL,则不需要相应的父表中的行。

4.2.延迟的外键约束

SQLite中的每个外键约束都被分类为立即数或延期。默认情况下,外键约束是直接的。提供的所有外键示例迄今为止,一直存在着直接的外键限制。

如果一个语句修改了数据库的内容外键约束违反了语句的结论,抛出异常,并且语句的效果将恢复。相比之下,如果语句修改数据库的内容,以便违反了外键约束,未报告违反情况立即。未检查延迟的外键约束直到事务尝试承诺.只要用户有一个打开的事务,允许数据库以以下状态存在违反了任意数量的延迟外键约束。然而,承诺只要外键约束保持在违反。

如果当前语句不在显式事务(开始/承诺/回降块),然后是隐式事务已提交只要语句执行完毕。在这种情况下,延期约束的行为与直接约束相同。

要将外键约束标记为延迟,其声明必须包括以下条款:

可延期初始延期--延迟的外键约束

指定外键约束的完整语法作为一部分提供创建表格文档。替换上面的短语具有以下任一项创建直接外键约束。

不可延期初始延期--直接外键约束最初不可立即延期--直接外键约束不可延期--直接外键约束可延迟初始立即--直接外键约束可延期--直接外键约束

这个defer_foreign_keys杂注可用于临时更改所有外来要延迟的键约束,无论它们是如何声明的。

下面的示例说明了使用延迟外文的效果键约束。

--数据库架构。这两个表最初都是空的。CREATE TABLE艺术家(artistid INTEGER主键,艺人姓名文本);CREATE TABLE曲目(trackid整数,轨道名称文本,trackartist INTEGER参考艺术家(artistid)可延期初始延期);sqlite3>--如果外键约束是立即的,则此INSERT将方形3>--导致错误(因为在表artist中没有行方形3>--artisti=5)。但随着约束被推迟方形3>--打开事务,没有发生错误。sqlite3>开始;sqlite3>插入轨道值(1,“白色圣诞节”,5);方形3>--以下COMMIT失败,因为数据库处于以下状态方形3>--不满足延迟的外键约束。这个方形3>--交易仍处于打开状态。sqlite3>提交;SQL错误:外键约束失败方形3>--在artisti=5的artist表中插入一行后方形3>--满足延迟的外键约束。那就有可能了方形3>--以无错误地提交事务。sqlite3>插入艺术家价值观(5,“Bing Crosby”);sqlite3>提交;

A类嵌套保存点交易可以在数据库处于不满足延迟外键的状态约束。事务保存点(一个非嵌套的保存点当前没有打开的事务时打开),在另一方面,受到与COMMIT相同的限制-尝试在数据库处于这种状态时释放它将失败。

如果COMMIT语句(或事务SAVEPOINT的RELEASE)失败因为数据库当前的状态违反了延迟外键约束,并且当前存在嵌套保存点,嵌套的保存点保持打开状态。

4.3.ON DELETE和ON UPDATE操作

外键ON DELETE和ON UPDATE子句用于配置操作从父表中删除行时发生(ON DELETE),或修改现有行的父键值(ON UPDATE)。一张单人床外键约束可以为ON DELETE配置不同的操作和ON UPDATE。外键操作在许多方面与触发器类似。

与中的每个外键关联的ON DELETE和ON UPDATE操作SQLite数据库是“NO ACTION”、“RESTRICT”、“SET NULL”、,“设置默认值”或“级联”。如果未显式指定操作默认为“无操作”。

例如,将“ON UPDATE CASCADE”子句添加到外键如下所示增强了第1节中的示例模式,以允许用户更新artistid(外键约束的父键)列而不破坏引用完整性:

--数据库架构CREATE TABLE艺术家(artistid INTEGER主键,艺人姓名文本);CREATE TABLE轨道(trackid整数,轨道名称文本,轨道艺术家INTEGER参考艺术家(艺术家)关于更新级联);sqlite>SELECT*FROM艺术家;艺人艺名--------  -----------------1迪安·马丁2弗兰克·辛纳特拉sqlite>SELECT*FROM曲目;trackid trackname轨迹艺术家-------  -----------------  -----------11那是阿莫里112圣诞布鲁斯113我的方式2sqlite公司>--更新“Dean Martin”艺术家记录的artistid栏。方形>--通常,这会产生一个约束,因为它会孤立这两个方形>--跟踪表中的相关记录。然而,ON UPDATE CASCADE子句方形>--附加到外键定义导致更新为“级联”方形>--以防止外键约束冲突。sqlite>UPDATE artist SET artistid=100 WHERE artistname='Dean Martin';sqlite>SELECT*FROM艺术家;艺人艺名--------  -----------------2弗兰克·辛纳特拉100迪安·马丁sqlite>SELECT*FROM曲目;trackid trackname轨迹艺术家-------  -----------------  -----------11这是Amore 10012圣诞布鲁斯10013我的路2

配置ON UPDATE或ON DELETE操作并不意味着键约束不需要满足。例如,如果配置了“ON DELETE SET DEFAULT”操作,但父表中没有行对应于子键列的默认值,删除存在从属子键时父键仍会导致外键违反。例如:

--数据库架构CREATE TABLE艺术家(artistid INTEGER主键,艺人姓名文本);CREATE TABLE曲目(trackid整数,轨道名称文本,轨迹艺术家INTEGER默认值0参考艺术家(artistid)删除集合默认值时);sqlite>SELECT*FROM艺术家;艺人艺名--------  -----------------3小萨米·戴维斯。sqlite>SELECT*FROM曲目;trackid trackname轨迹艺术家-------  -----------------  -----------14 Bojangles先生3方形>--从父表中删除行会导致子键方形>--要设置为整数值0的从属行的值。然而,这方形>--值与父表中的任何行都不对应。因此方形>--违反了外键约束并引发了is异常。sqlite>从艺术家删除WHERE artistname='Sammy Davis Jr.';SQL错误:外键约束失败方形>--这一次,值0确实对应于父表行。而且sqlite公司>--因此DELETE语句不会违反外键约束方形>--并且没有抛出异常。sqlite>插入艺术家值(0,“未知艺术家”);sqlite>从艺术家删除WHERE artistname='Sammy Davis Jr.';sqlite>SELECT*FROM艺术家;艺人艺名--------  -----------------0未知艺术家sqlite>SELECT*FROM曲目;trackid trackname轨迹艺术家-------  -----------------  -----------14 Bojangles先生0

熟悉的人SQLite触发器会注意到上面示例中演示的“ON DELETE SET DEFAULT”操作是与以下AFTER DELETE触发器的效果类似:

在艺术家开始删除后创建触发器on_delete_set_default更新子集合trackartist=0 WHERE trackartir=old.artistid;结束;

每当删除外键约束的父表中的行时,或者修改存储在父键列中的值时,事件的逻辑顺序是:

  1. 执行适用的BEFORE触发程序,
  2. 检查本地(非外键)约束,
  3. 更新或删除父表中的行,
  4. 执行任何必需的外键操作,
  5. 执行适用的AFTER触发程序。

ON-UPDATE外键操作和SQL触发器。只有在修改父键,以便新的父键值不等于老年人。例如:

--数据库架构CREATE TABLE父项(x主键);CREATE TABLE子项(y在更新集为NULL时引用父项);sqlite>SELECT*FROM父级;x个----钥匙sqlite>SELECT*FROM子级;----钥匙方形>--由于以下UPDATE语句实际上并没有修改方形>--父键值,则不会执行ON UPDATE操作,并且方形>--子键值未设置为NULL。sqlite>UPDATE父SET x='key';sqlite>SELECT IFNULL(y,'null')FROM子级;----钥匙方形>--这一次,因为UPDATE语句确实修改了父键方形>--值,则执行ONUPDATE操作并设置子键sqlite公司>--设置为NULL。sqlite>UPDATE父SET x='key2';sqlite>SELECT IFNULL(y,'null')FROM子级;----无效的

5CREATE、ALTER和DROP TABLE命令

本节描述了创建表格,ALTER表格,DROP表格命令与SQLite的外键交互。

A类创建表格命令的操作与否相同已启用外键约束。的父键定义创建表时不检查外键约束。没有什么可以阻止用户创建一个外键定义引用不存在的父表,或引用不存在或不受主键或唯一的共同约束约束。

这个ALTER表格在国外,命令在两个方面的工作方式不同关键约束已启用:

如果在准备时启用了外键约束,则DROP表格命令执行隐式删除删除所有删除表之前从表中删除行。隐式DELETE不会导致任何要触发的SQL触发器,但可能会调用外键操作或约束违规行为。如果违反了直接外键约束,则DROPTABLE语句失败,表未被删除。如果延期外国违反了键约束,则在用户尝试时报告错误如果仍然违反外键约束,则提交事务在那一点上存在。作为一部分,遇到任何“外键不匹配”错误将忽略隐式DELETE的。

这些增强功能的目的是ALTER表格DROP表格命令是为了确保它们不能用于创建包含外键冲突,至少外键约束是启用。但这条规则有一个例外。如果父键为不受作为父表定义,但受制于UNIQUE约束使用创建索引命令,然后是子级可以填充表而不会导致“外键不匹配”错误。如果从数据库模式中删除UNIQUE索引,然后删除父表本身被丢弃,不会报告任何错误。然而,数据库可能处于外键约束的子表包含不引用任何父表行的行。这种情况可以避免如果数据库架构中的所有父键都受PRIMARY KEY约束或作为父表定义的一部分添加的UNIQUE约束,而不是通过外部UNIQUE索引。

的属性DROP表格ALTER表格描述的命令以上仅适用于启用外键的情况。如果用户认为不受欢迎,那么解决方法是使用PRAGMA外文_键在执行DROP或ALTER TABLE之前禁用外键约束命令。当然,虽然外键约束被禁用,但什么都没有阻止用户违反外键约束,从而创建内部不一致的数据库。

6限制和不支持的功能

本节列出了一些限制和省略的功能其他地方提到的。

  1. 不支持MATCH子句。根据SQL92,MATCH子句可以附加到复合外键定义以修改方式处理子键中出现的NULL值。如果“MATCH SIMPLE”为指定,则不需要子键来对应任何行如果一个或多个子键值为NULL,则返回父表的。如果指定了“MATCH FULL”,则如果任何子键值为NULL,父表中不需要相应的行,但所有子键值必须为NULL。最后,如果外键约束声明为“MATCH PARTIAL”,其中一个子键值为NULL,父表中必须至少存在一行非NULL子键值与父键值匹配。

    SQLite解析MATCH子句(即不报告语法错误如果指定了一个),但不强制执行它们。所有外键SQLite中的约束处理方式就像指定了MATCH SIMPLE一样。

  2. 不支持在延迟和立即之间切换约束模式。许多系统允许用户切换单个外键之间的约束推迟和立即模式(例如使用Oracle“SET CONSTRAINT”命令)。SQLite不支持此功能。在SQLite中,外键约束是创建时永久标记为延迟或立即。

  3. 外键操作的递归限制。这个SQLITE_MAX_TRIGGER_DEPTH公司SQLITE_LIMIT_TRIGGER_DEPTH公司设置确定触发器的最大允许深度程序递归。就这些限制而言,外键操作被认为是触发程序。这个PRAGMA递归触发器设置不影响操作外键操作。无法禁用递归外部关键行动。

  4. 外键不能跨越架构边界。也就是说,在参考文献(X.Y)桌子X(X)只能解决在包含参考文献条款。

此页面上次修改时间2024-01-23 13:08:17联合技术公司