SQLite 入门教程三 好多约束 Constraints
一、约束 constraints
在上一篇随笔的结尾,我提到了约束, 但是在那里我把它翻译成了限定符,不太准确,这里先更正一下,应该翻译成约束更贴切一点。 那么什么是约束呢?
我们在数据库中存储数据的时候,有一些数据有明显的约束条件。 比如一所学校关于教师的数据表,其中的字段列可能有如下约束:
年龄 - 至少大于20岁。如果你想录入一个小于20岁的教师,系统会报错
国籍 - 默认中国。所谓默认,就是如果你不填写,系统自动填上默认值
姓名 - 不能为空。每个人都有名字嘛
员工号 - 唯一。这个可不能乱,工资发错了就麻烦了
上面提到的大于、默认、不能为空、唯一等等,就是数据的约束条件。 我们在用 create table 创建表的时候,就应该将每个字段列的约束条件事先说明(如果有的话), 以后再往表里输入数据的时候,系统会自动为我们检查是否满足约束条件,如果不满足系统会报错。
sqlite 常用约束如下
not null - 非空
unique - 唯一
primary key - 主键
foreign key - 外键
check - 条件检查
default - 默认
二、主键 primary key
我们还是进入 sqlite 命令行环境,建立一个 test.db 数据库用来做实验,如下
运行 .tables 命令没有返回,说明数据库是空的。如果你的数据库里面有内容并影响到下面的实验, 你可以用我们上一篇学的 drop table 来删除造成影响的表, 或者用 alter table ... rename to ... 来改名。
--------------------------------------------------------------------------------
下面言归正转,我们来说说主键 primary key 。
首先,数据表中每一条记录都有一个主键, 这就像我们每的身份证号码、员工号、银行帐号; 反过来也可以说,每一个主键对应着一条数据记录。 所以,主键必须是唯一的。
其次,一般情况下主键同时也是一个索引,所以通过主键查找记录速度比较快。
第三,在关系型数据库中,一个表的主键可以作为另外一个表的外键, 这样,这两个表之间就通过这个键建立了关系。
最后,主键一般是整数或者字符串,只要保证唯一就行。 在 sqlite 中,主键如果是整数类型,该列的值可以自动增长。
--------------------------------------------------------------------------------
下面我们来做实验
--------------------------------------------------------------------------------
我们先新建了一个 teachers 表,并设置了两个字段列,其中 id 字段列为主键列。 然后,我们向其中插入三条数据并查询,反馈一切正常。
注意:在插入前三条数据的时候,命令中并没有明确指明 id 的值,系统自动赋值,并且数值自动增长。
插入第四条数据的时候,我给了一个明确的 id 编号为 2,因为李四的编号已经是 2 了, 所以系统提示我错误:主键必须唯一。
三、默认值 default
有一些特别的字段列,在每一条记录中,他的值基本上都是一样的。只是在个别情况下才改为别的值,这样的字段列我们可以给他设一个默认值。
下面我们来做实验
先把之前的 teachers 表删除,然后重新创建。这回 teachers 表多了一个 country 字段, 并且设置默认值为“中国”,然后我们插入四条数据到 teachers 表。
前三条数据都没有明确指明 country 字段的值,只有第四条数据指明了“孙悟空”的 country 为“天庭”。
查询数据,发现前三条数据都填上了默认值,实验成功。
--------------------------------------------------------------------------------
数据显示有点走样,命令 .width 4 15 15 设置的列宽,可以通过 .show 查看, 可能是因为中文的原因,所以没有对齐。
四、非空 not null
有一些字段我们可能一时不知到该填些什么,同时它也没设定默认值, 当添加数据时,我们把这样的字段空着不填,系统认为他是 null 值。
但是还有另外一类字段,必须被填上数据,如果不填,系统就会报错。 这样的字段被称为 not null 非空字段,需要在定义表的时候事先声明。
下面我们来做实验
还是先删除旧表,创建新表。
这回 teachers 表声明了一个 not null 字段 age,同时还有一个可以为 null 的字段 city
插入前三条数据都没有指定 city 的值,查询可以看到 city 字段全部为空
注意:这里的 null 只是对“什么都没有”的一种显示形式, 可以通过 .nullvalue 命令改为别的形式,具体见第一篇
插入第四条数据时没有指定 age 的值,系统就报错了: teachers.age 不能为空
五、 唯一 unique
这一约束很好理解,除了主列以为,还有一些列也不能有重复值。不多说,直接看代码
这次的 teachers 表只有 name 这一列,但是 name 列不能有重复值。可以看到,到我们第二次插入 bob 时,系统就报错了。
六、 条件检查 check
某些值必须符合一定的条件才允许存入,这是就需要用到这个 check 约束。
age 字段要求必须大于 22,当插入的数据小于22时,系统报错。
七、外键 foreign key
现在,我们的数据库中已经有 teachers 表了,假如我们再建立一个 students 表, 要求 students 表中的每一个学生都对应一个 teachers 表中的教师。
很简单,只需要在 students 表中建立一个 teacherid 字段,保存对应教师的 id 号, 这样,学生和教师之间就建立了关系。
--------------------------------------------------------------------------------
问题是:我们有可能给学生存入一个不在 teachers 表中的 teacherid 值, 而且发现不了这个错误。
这种情况下,可以把 students 表中 teacherid 字段声明为一个外键, 让它的值对应到 teachers 表中的 id 字段上。
这样,一旦在 students 表中存入一个不存在的教师 id ,系统就会报错。
这里建立了 students 表,并且把 teacherid 作为外键与 teachers 表的 id 列相对应。
问题来了:插入的前两条数据没问题,因为 id 编号 1、3 都在 teachers 表中; 但是数字 9 并不在 teachers 表中,不但没有报错,系统还保存进去了,这是为什么呢?
据说 sqlite 的外键约束默认情况下并不是开启的,如果你需要这个功能,你可能需要下载源代码版本,设置每个编译参数,然后重新编译,这样你就得到支持外键的 sqlite 了。
上一篇: SQLite 内存数据库学习手册
下一篇: SQLite3 命令行操作指南