当前位置: 移动技术网 > IT编程>数据库>SQLLite > SQLite 入门教程三 好多约束 Constraints

SQLite 入门教程三 好多约束 Constraints

2017年11月30日  | 移动技术网IT编程  | 我要评论

一、约束 constraints

在上一篇随笔的结尾,我提到了约束, 但是在那里我把它翻译成了限定符,不太准确,这里先更正一下,应该翻译成约束更贴切一点。 那么什么是约束呢?

我们在数据库中存储数据的时候,有一些数据有明显的约束条件。 比如一所学校关于教师的数据表,其中的字段列可能有如下约束:

年龄 - 至少大于20岁。如果你想录入一个小于20岁的教师,系统会报错
国籍 - 默认中国。所谓默认,就是如果你不填写,系统自动填上默认值
姓名 - 不能为空。每个人都有名字嘛
员工号 - 唯一。这个可不能乱,工资发错了就麻烦了
上面提到的大于、默认、不能为空、唯一等等,就是数据的约束条件。 我们在用 create table 创建表的时候,就应该将每个字段列的约束条件事先说明(如果有的话), 以后再往表里输入数据的时候,系统会自动为我们检查是否满足约束条件,如果不满足系统会报错。


sqlite 常用约束如下

not null - 非空
unique - 唯一
primary key - 主键
foreign key - 外键
check - 条件检查
default - 默认

二、主键 primary key

我们还是进入 sqlite 命令行环境,建立一个 test.db 数据库用来做实验,如下

复制代码 代码如下:

myqiao@ubuntu:~/my documents/db$ sqlite3 test.db
-- loading resources from /home/myqiao/.sqliterc
sqlite version 3.7.4
enter ".help" for instructions
enter sql statements terminated with a ";"
sqlite> .tables
sqlite> 

            运行 .tables 命令没有返回,说明数据库是空的。如果你的数据库里面有内容并影响到下面的实验, 你可以用我们上一篇学的 drop table 来删除造成影响的表, 或者用 alter table ... rename to ... 来改名。


--------------------------------------------------------------------------------

下面言归正转,我们来说说主键 primary key 。

首先,数据表中每一条记录都有一个主键, 这就像我们每的身份证号码、员工号、银行帐号; 反过来也可以说,每一个主键对应着一条数据记录。 所以,主键必须是唯一的。
其次,一般情况下主键同时也是一个索引,所以通过主键查找记录速度比较快。
第三,在关系型数据库中,一个表的主键可以作为另外一个表的外键, 这样,这两个表之间就通过这个键建立了关系。
最后,主键一般是整数或者字符串,只要保证唯一就行。 在 sqlite 中,主键如果是整数类型,该列的值可以自动增长。

--------------------------------------------------------------------------------

下面我们来做实验

复制代码 代码如下:

sqlite> 
sqlite> create table teachers(id integer primary key,name text);
sqlite> .tables
teachers
sqlite> insert into teachers(name) values('张三');
sqlite> insert into teachers(name) values('李四');
sqlite> insert into teachers(name) values('王二麻子');
sqlite> select * from teachers;
id          name     
----------  ----------
1           张三   
2           李四   
3           王二麻
sqlite> insert into teachers(id,name) values(2,'孙悟空');
error: primary key must be unique
sqlite> 
      
--------------------------------------------------------------------------------

我们先新建了一个 teachers 表,并设置了两个字段列,其中 id 字段列为主键列。 然后,我们向其中插入三条数据并查询,反馈一切正常。

注意:在插入前三条数据的时候,命令中并没有明确指明 id 的值,系统自动赋值,并且数值自动增长。

插入第四条数据的时候,我给了一个明确的 id 编号为 2,因为李四的编号已经是 2 了, 所以系统提示我错误:主键必须唯一。

三、默认值 default

有一些特别的字段列,在每一条记录中,他的值基本上都是一样的。只是在个别情况下才改为别的值,这样的字段列我们可以给他设一个默认值。

下面我们来做实验

复制代码 代码如下:

sqlite> 
sqlite> drop table teachers;
sqlite> .tables
sqlite>
sqlite> create table teachers(id integer primary key,name text,country text default '中国');
sqlite> .tables
teachers
sqlite> insert into teachers(name) values('张三');
sqlite> insert into teachers(name) values('李四');
sqlite> insert into teachers(name) values('王二麻子');
sqlite> insert into teachers(name,country) values('孙悟空','天庭');
sqlite> select * from teachers;
id    name             country       
----  ---------------  ---------------
1     张三           中国        
2     李四           中国        
3     王二麻子     中国        
4     孙悟空        天庭
sqlite>

            先把之前的 teachers 表删除,然后重新创建。这回 teachers 表多了一个 country 字段, 并且设置默认值为“中国”,然后我们插入四条数据到 teachers 表。

前三条数据都没有明确指明 country 字段的值,只有第四条数据指明了“孙悟空”的 country 为“天庭”。

查询数据,发现前三条数据都填上了默认值,实验成功。

--------------------------------------------------------------------------------
数据显示有点走样,命令 .width 4 15 15 设置的列宽,可以通过 .show 查看, 可能是因为中文的原因,所以没有对齐。

四、非空 not null

有一些字段我们可能一时不知到该填些什么,同时它也没设定默认值, 当添加数据时,我们把这样的字段空着不填,系统认为他是 null 值。

但是还有另外一类字段,必须被填上数据,如果不填,系统就会报错。 这样的字段被称为 not null 非空字段,需要在定义表的时候事先声明。

下面我们来做实验

复制代码 代码如下:

sqlite> 
sqlite> drop table teachers;
sqlite> .tables
sqlite>
sqlite> create table teachers(id integer primary key,name text,age integer not null,city text);
sqlite> .tables
teachers
sqlite> insert into teachers(name,age) values('alice',23);
sqlite> insert into teachers(name,age) values('bob',29);
sqlite> insert into teachers(id,name,age) values(6,'jhon',36);
sqlite> select * from teachers;
id    name             age              city          
----  ---------------  ---------------  ---------------
1     alice            23               null          
2     bob              29               null          
6     jhon             36               null          
sqlite> insert into teachers(name) values('mary');
error: teachers.age may not be null
sqlite>

            还是先删除旧表,创建新表。

这回 teachers 表声明了一个 not null 字段 age,同时还有一个可以为 null 的字段 city

插入前三条数据都没有指定 city 的值,查询可以看到 city 字段全部为空

注意:这里的 null 只是对“什么都没有”的一种显示形式, 可以通过 .nullvalue 命令改为别的形式,具体见第一篇

插入第四条数据时没有指定 age 的值,系统就报错了: teachers.age 不能为空

五、 唯一 unique
这一约束很好理解,除了主列以为,还有一些列也不能有重复值。不多说,直接看代码

复制代码 代码如下:

sqlite> 
sqlite> drop table teachers;
sqlite> .tables
sqlite>
sqlite> create table teachers(id integer primary key,name text unique);
sqlite> .tables
teachers
sqlite> insert into teachers(name) values('alice');
sqlite> insert into teachers(name) values('bob');
sqlite> insert into teachers(name) values('jane');
sqlite> insert into teachers(name) values('bob');
error: column name is not unique
sqlite>

            这次的 teachers 表只有 name 这一列,但是 name 列不能有重复值。可以看到,到我们第二次插入 bob 时,系统就报错了。

六、 条件检查 check

某些值必须符合一定的条件才允许存入,这是就需要用到这个 check 约束。

复制代码 代码如下:

sqlite> 
sqlite> drop table teachers;
sqlite> .tables
sqlite>
sqlite> create table teachers(id integer primary key,age integer check(age>22));
sqlite> .tables
teachers
sqlite> insert into teachers(age) values(45);
sqlite> insert into teachers(age) values(33);
sqlite> insert into teachers(age) values(23);
sqlite> insert into teachers(age) values(21);
error: constraint failed
sqlite>

            age 字段要求必须大于 22,当插入的数据小于22时,系统报错。

七、外键 foreign key

现在,我们的数据库中已经有 teachers 表了,假如我们再建立一个 students 表, 要求 students 表中的每一个学生都对应一个 teachers 表中的教师。

很简单,只需要在 students 表中建立一个 teacherid 字段,保存对应教师的 id 号, 这样,学生和教师之间就建立了关系。

--------------------------------------------------------------------------------

问题是:我们有可能给学生存入一个不在 teachers 表中的 teacherid 值, 而且发现不了这个错误。

这种情况下,可以把 students 表中 teacherid 字段声明为一个外键, 让它的值对应到 teachers 表中的 id 字段上。

这样,一旦在 students 表中存入一个不存在的教师 id ,系统就会报错。

复制代码 代码如下:

sqlite>
sqlite> .tables
teachers
sqlite> create table students (id integer primary key,  teacherid integer,  foreign key(teacherid) references teachers(id) );
sqlite> .tables
students  teachers
sqlite> select * from teachers;
id    age           
----  ---------------
1     40            
2     33            
3     23
sqlite> insert into students(teacherid) values(1);
sqlite> insert into students(teacherid) values(3);
sqlite> insert into students(teacherid) values(9);
sqlite> select * from students;
id    teacherid     
----  ---------------
1     1             
2     3             
3     9
sqlite>

这里建立了 students 表,并且把 teacherid 作为外键与 teachers 表的 id 列相对应。

问题来了:插入的前两条数据没问题,因为 id 编号 1、3 都在 teachers 表中; 但是数字 9 并不在 teachers 表中,不但没有报错,系统还保存进去了,这是为什么呢?

据说 sqlite 的外键约束默认情况下并不是开启的,如果你需要这个功能,你可能需要下载源代码版本,设置每个编译参数,然后重新编译,这样你就得到支持外键的 sqlite 了。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网