`

SQLite外键(Foreign Key)支持

阅读更多
[size=x-large]SQLite外键(Foreign Key)支持
从SQLite 3.6.19 开始支持 外键约束. (Ubuntu 10.04 的SQLite版本是 3.6.22,  Debian 6.0 的SQLite版本是  3.7.0)
外键约束用来强制 两个表之间”存在”的关系. 比如, 考虑下面的SQL命令建立的schema
CREATE TABLE artist(
artistid INTEGER PRIMARY KEY,
artistname TEXT
);
CREATE TABLE track(
trackid INTEGER,
trackname TEXT,
trackartist INTEGER — 必须映射到一个 artist.artistid 记录
);
使用这个数据库的应用可以假定: 对于在track表里每一行, 都在artist表都存在一个对应的行.   不幸的是, 如果用户使用外部工具编辑数据库, 或者在应用程序中存在一个bug. 那么可能在track表中插入一行,而在artist表中没有相应的记录. 或者, 在artist表中删除某些行,  就会在track表里留下孤儿行(orphaned rows),  它们在artist表中剩下的记录找到任何对应的行.  这可能在以后会导致应用的功能出错. 或者至少让编写应用程序更复杂.
一个解决方法就是, 为数据库添加一个外键约束,在artist和track这两个表之间强制实施一个约束. 增加外键定义的track表的定义如下:
CREATE TABLE track(
trackid     INTEGER,
trackname   TEXT,
trackartist INTEGER,
FOREIGN KEY(trackartist) REFERENCES artist(artistid)
);
这样,外键约束就由SQLite强制实施.  往 track表插入一行 在 artist表中没有对应的数据的记录的企图注定是要失败的,o(∩∩)o
如果在track表还存在依赖于artist中的某行的记录, 那么尝试从 artist表删除该行, 也会失败.
也就是说, 对于在track表中的每一行,,下面的表达式都是真:
trackartist IS NULL OR EXISTS(SELECT 1 FROM artist WHERE artistid=trackartist)
在SQLite中启用外键支持
1)为了在SQLite中使用外键约束, 编译sqlite库时, 不能使用 忽略 外键和触发器, 也就是 SQLITE_OMIT_FOREIGN_KEY 和 SQLITE_OMIT_TRIGGER不能被定义
2)必须在运行时打开, 因为  默认是关闭的
PRAGMA foreign_keys = ON;
要求和建议的数据库索引
通常, 外键约束的父键在父表里是主键. 如果它们不是主键, 那么父键栏 必须受一个UNIQUE约束 或者 有一个 UNIQUE 索引.
如果数据库schema还有外键错误, 就需要查看多个表才能找到错误. 数据表创建时不会检测这些错误,
这些错误会阻止应用程序 用SQL语句来修改子表或者父表的内容. 当内容被改变时,报告”DML errors”;当schema被改变时报告”DDL errors”
也就是说,错误地配置外键约束,要求检查子表和父表的是DML错误, 一般显示”foreign key mismatch” 或者 “no such table”
SELECT rowid FROM <child-table> WHERE <child-key> = :parent_key_value
如果这个SELECT返回数据, 那么SQLite就断定, 从父表删除某行, 将会违背外键约束,并返回错误. 如果父键的值被修改或者在父表插入新的一行,也会产生类似的查询.
如果这些查询没有使用索引, 它们将强迫对整个子表做线性 查找(scan), 这代价可太大了
在大多数实际系统中,  应该在子键这一栏建立索引. 子键的索引不必(并且是通常都不必) 有一个UNIQUE 索引(因为在子表中的多行对应于父表中的一行)
CREATE INDEX trackindex ON track(trackartist);
ON DELETE 和 ON UPDATE行为
外键的ON DELETE和 ON  UPDATE从句, 可以用来配置  当从父表中删除 某些行时发生的行为(ON DELETE).  或者 修改存在的行的父键的值, 发生的行为(ON UPDATE)
单个外键约束可以为ON DELETE和ON UPDATE配置不同的行为.   外键行为在很多时候类似于 触发器(trigger)
ON DELETE和ON UPDATE的行为是 NO ACTION,  RESTRICT, SET NULL,  SET DEFAULT 或者 CASCADE
如果没有明确指定星闻,那么默认就是NO ACTION
NO ACTION: 当父键被修改或者删除时, 没有特别的行为发生
RESTRICT:  存在一个或者多个子键对应于相应的父键时,  应用程序禁止删除(ON DELETE RESTRICT)或者修改(ON UPDATE RESTRICT) 父键
RESTRICT与普通的外键约束的区别是,  当字段(field)更新时, RESTRICT行为立即发生
SET NULL: 父键被删除(ON DELETE SET NULL) 或者修改 (ON UPDATE SET NULL)
SET DEFAULT: 类似于SET NULL
CASCADE: 将实施在父键上的删除或者更新操作,传播给与之关联的子键.
对于 ON DELETE CASCADE, 同被删除的父表中的行 相关联的子表中的每1行,也会被删除.
对于ON UPDATE CASCADE,  存储在子表中的每1行,对应的字段的值会被自动修改成同新的父键匹配
举例:
CREATE TABLE artist(
artistid    INTEGER PRIMARY KEY,
artistname  TEXT
);
CREATE TABLE track(
trackid     INTEGER,
trackname   TEXT,
trackartist INTEGER REFERENCES artist(artistid) ON UPDATE CASCADE
);
INSERT INTO artist VALUES(1, ‘Dean Martin’);
INSERT INTO artist VALUES(2, ‘Frank Sinatra’);
INSERT INTO track VALUES(14, ‘Mr. Bojangles’, 2);
INSERT INTO track VALUES(15, “That’s Amore”, 2);
INSERT INTO track VALUES(12, ‘Christmas Blues’, 1);
INSERT INTO track VALUES(13, ‘My Way’, 2);
sqlite> PRAGMA foreign_keys = ON;
(默认是关闭的, 要在运行时打开)
sqlite> SELECT * FROM artist;
1|Dean Martin
2|Frank Sinatra
sqlite> SELECT * FROM track;
14|Mr. Bojangles|2
15|That’s Amore|2
12|Christmas Blues|1
13|My Way|2
sqlite> UPDATE artist SET artistid = 999 WHERE artistname = ‘Dean Martin’;
(为 Dean Martin更改 artist表中的artistid栏目.
一般情况下, 这将 产生一个约束, 因为会让 track表中的 一条记录成为孤儿记录
但 对外键定义使用了ON UPDATE CASCADE从句后,  会把这个更新传给 子表, 从而让外键约束不被打破)
sqlite> SELECT * FROM artist;
2|Frank Sinatra
999|Dean Martin
sqlite> SELECT * FROM track;
14|Mr. Bojangles|2
15|That’s Amore|2
12|Christmas Blues|999
13|My Way|2
配置一个ON UPDATE或者ON DELETE行为并不意味着 外键约束 并不必要满足.
举例来说, 如果 配置了 ON DELETE SET DEFAULT 行为, 如果在父表中没有 与子表栏目中默认值 相对应 的 行记录, 当依赖的子键存在于子表中是, 删除父键, 会破坏外键.
举例:
sqlite> PRAGMA foreign_keys = ON;
CREATE TABLE artist(
artistid INTEGER PRIMARY KEY,
artistname TEXT
);
CREATE TABLE track(
trackid INTEGER,
trackname TEXT,
trackartist INTEGER DEFAULT 0 REFERENCES artist(artistid) ON DELETE SET DEFAULT
);
INSERT INTO artist VALUES(3, ‘Sammy Davis Jr.’);
INSERT INTO track VALUES(14, ‘Mr. Bojangles’, 3);
sqlite> DELETE FROM artist WHERE artistname = ‘Sammy Davis Jr.’;
Error: foreign key constraint failed
从父表中删除一行, 会引起子表中相关的子键被设置成整数0
然而, 这个值不对应与 附表中的任何一行数据. 所以,外键约束被打破, 就抛出了异常
sqlite> INSERT INTO artist VALUES(0, ‘Unknown Artist’);
往父表中添加一行, 其主键为0
这样删除记录就不会打破外键约束了
sqlite> DELETE FROM artist WHERE artistname = ‘Sammy Davis Jr.’;
sqlite> SELECT * FROM artist;
0|Unknown Artist
sqlite> SELECT * FROM track;
14|Mr. Bojangles|0
这写都很类似于 SQLite 触发器(triggers), ON DELETE SET DEFAULT行为, 在效果上, 同下面的 AFTER DELETE 触发器是类似的
CREATE TRIGGER on_delete_set_default AFTER DELETE ON artist BEGIN
UPDATE child SET trackartist = 0 WHERE trackartist = old.artistid;
END;
外键约束的父表中的某行被删除, 或者存储在父键中的值 被修改时: 时间的逻辑顺序是:
1. 执行在BEFORE 触发器程序
2. 检查本地(非外键)约束
3. 在父表中 更新或者删除行
4. 执行要求的外键行为
5. 执行 AFTER触发器 程序
在ON UPDATE外键行为 和 SQL 触发器之间一个重要区别就是, ON UPDATE 行为只有在 父键的值 被修改并且父键的值修改得跟原来不一样时,才执行.
如果下UPDATE SET 语句修改的值,跟原来一样, ON UPDATE行为不会执行
[/size]
分享到:
评论

相关推荐

    sqlite3-3.26.0.zip

    这个"sqlite3-3.26.0.zip"压缩包包含的是 SQLite3 的特定版本——V3.26.0,它经过了重新编译,并且在默认情况下启用了外键约束功能。这一改动意味着在使用这个版本的 SQLite3 时,你无需在 SQL 命令中额外设置来启用...

    完整版生成Sqlite表结构.rar

    例如,可以使用外键(FOREIGN KEY)来确保两个表之间的关系,如: ```sql CREATE TABLE Orders ( OrderID INTEGER PRIMARY KEY, UserID INTEGER, Product TEXT, FOREIGN KEY (UserID) REFERENCES Users(ID) ); ...

    LKDBHelper外键

    首先,我们需要理解什么是外键(Foreign Key)。在关系型数据库中,外键是一种约束,用于建立和加强两个表之间的联系。它是一个或一组字段,其值来源于另一个表的主键,用于确保数据的一致性和完整性。外键的存在...

    数据库Sqlite的备忘录

    9. 外键(Foreign Key)与约束(Constraint): SQLite支持外键,用于建立表之间的关联。创建带有外键的表: ```sql CREATE TABLE Courses ( CourseID INTEGER PRIMARY KEY, CourseName TEXT, TeacherID ...

    sqlite3数据库入门

    - **外键(FOREIGN KEY)**:通过定义外键约束,可以确保一个表中的某个字段的值必须存在于另一个表的主键中。例如,Students表中的`TeacherId`字段必须存在于Teachers表的`Id`字段中。 #### 八、常用命令 - **.help*...

    SQLite 中文帮助pdf

    PRAGMA foreign_key_list(table-name); 对于参数表中每个涉及到字段的外键,使用该外键的信息调用一次回叫函数。每个外键中的每个字段都将调用一次回叫函数。 PRAGMA index_info(index-name); 对该索引涉及到的每个...

    sqlite-doc-3340000.zip

    8. 外键(FOREIGN KEY):SQLite3支持外键约束,实现不同表之间的数据关联,保证数据的一致性。 9. 兼容性和移植性:SQLite3具有广泛的平台兼容性,可以在多种操作系统上运行,并且它的API设计使得代码容易在不同...

    sqlite3实验指导书

    - FOREIGN KEY:外键约束,用于在两个表之间建立关联,保证引用的完整性。 - CHECK:条件检查约束,用于限制列值必须满足的条件。 然后,文档中提到SQLite的一些基本操作命令。例如,可以通过以下命令进入SQLite的...

    SQLite CRUD

    FOREIGN KEY (department_id) REFERENCES Departments(id) ); CREATE TABLE Departments ( id INTEGER PRIMARY KEY, name TEXT ); ``` 这里,`Employees`表的`department_id`字段引用`Departments`表的`id`,...

    Android开发学习教程—Android使用SQLite数据库

    尽管SQLite几乎遵循SQL-92标准,但它省略了一些高级特性,如外键约束(Foreign Key constrains)、嵌套事务(Nested transactions)、右外部连接(RIGHT OUTER JOIN)和全外部连接(FULL OUTER JOIN),以及部分ALTER TABLE...

    将外键助手添加到迁移中,并将外键正确地转储到schema.rb-Ruby开发

    外国人外国人为您的迁移引入了一些添加和删除外键约束的方法。...迁移DSL通过add_foreign_key和remove_foreign_key开箱即用地支持外键安装将以下内容添加到您的Gemfile中:gem'foreigner'API示例外国人添加了tw

    sqlite数据库增删改查 不适用第三方数据库操作 一个数据库同时建多张表

    同时,不同表之间的数据关联可以通过外键(FOREIGN KEY)来实现,以维护数据的一致性和完整性。 在TestSqlite项目中,我们可以看到如何在单个SQLite数据库中创建并管理多个表的实例。通过这样的实践,开发者可以更...

    AndroidInject增加sqlite3数据库映射注解(ORM)

    4. `@ForeignKey`: 定义外键关系,用于关联不同的表,如: ```java @Entity(tableName = "orders", foreignKeys = @ForeignKey(entity = User.class, parentColumns = "id", childColumns = "userId")) public class...

    Android Database SQLite 多表操作源码

    SQLite支持多种数据库操作,包括创建、查询、更新和删除等,尤其在处理多表操作时,能够帮助开发者实现复杂的数据关联和业务逻辑。本源码示例专注于Android数据库SQLite的多表操作,适用于那些希望深入理解并实践...

    Sqlite的安装,使用,更新

    同时,可以通过`FOREIGN KEY`定义外键约束,维护数据的引用完整性。 5. **视图**:视图是基于一个或多个表的虚拟表,可以创建并使用视图来简化复杂的查询,如`CREATE VIEW student_view AS SELECT id, name FROM ...

    django在开发中取消外键约束的实现

    记得在完成操作后恢复外键检查,可以设置 `init_command` 为 `SET foreign_key_checks = 1;`。 在 Django 中处理外键关系时,有几种常用的方法: 1. **反查**:Django 自动为每个外键创建一个反向查询名称,通常是...

    SQLite的SQL语法

    - **FOREIGN KEY**: 外键约束,用于定义与另一个表的关联关系。 ##### 3.2 ALTER TABLE 用于修改表结构,如增加或删除列、修改列属性等。 ##### 3.3 DROP TABLE 用于删除整个表及其所有数据。 #### 四、索引 - ...

    android SQLite 一个数据库创建多个表

    SQLite是一个轻量级的、嵌入式的、关系型数据库,它不需要单独的服务器进程,并且支持SQL标准。在Android系统中,每个应用程序都可以拥有自己的SQLite数据库,这对于存储和管理应用程序的数据非常有用。本篇文章将...

    Android-SQLite3_超基础入门

    - **其他特性**:SQLite不支持某些传统关系数据库所具备的功能,例如`FOREIGN KEY`外键约束、`RIGHT OUTER JOIN`和`FULL OUTER JOIN`等。 #### 三、配置与环境准备 在开始使用SQLite之前,需要确保已经配置好了...

Global site tag (gtag.js) - Google Analytics