约束
约束也叫完整性约束(integrity constraint )
什么叫完整性?
完整性约束就是确保数据库中的数据是有意义的、正确的
什么是约束?
为了保证数据的正确性,对关系模型提出的某些约束条件或者是规则。
约束一般作用于字段上
约束有哪些?
非空、唯一、默认值、主键、外键、自增
语法:
字段名 字段类型 [not null | unique | default 默认值 | auto_increment]
1、默认值
mysql> use up;
Database changed
mysql> create table tdef (name char(10),city char(10) default 'shenyang');
mysql> desc tdef;
+-------+----------+------+-----+----------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+----------+-------+
| name | char(10) | YES | | NULL | |
| city | char(10) | YES | | shenyang | |
+-------+----------+------+-----+----------+-------+
mysql> insert into tdef values();
mysql> select * from tdef;
+------+----------+
| name | city |
+------+----------+
| NULL | shenyang |
+------+----------+
1 row in set (0.00 sec)
默认值:当用户向表中插入数据时,若指定该字段的值,那么就插入指定值;如果没有指定该字段的值,那么就插入默认值。
mysql> insert into tdef values('huangtao','qiqihaer');
mysql> select * from tdef;
+----------+----------+
| name | city |
+----------+----------+
| NULL | shenyang |
| huangtao | qiqihaer |
+----------+----------+
对于已经存在的表,如何设置字段的默认值
mysql> alter table tdef modify name char(10) default 'mary';
2、非空 not null
mysql> create table tnn (id int not null,name char(10));
mysql> insert into tnn values(); //会将不允许为空的id字段值转换成0
mysql> show warnings;
+---------+------+-----------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------+
| Warning | 1364 | Field 'id' doesn't have a default value |
+---------+------+-----------------------------------------+
mysql> select * from tnn;
+----+------+
| id | name |
+----+------+
| 0 | NULL |
+----+------+
1 row in set (0.00 sec)
mysql> desc tnn;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| name | char(10) | YES | | NULL | |
+-------+----------+------+-----+---------+-------+
mysql> alter table tnn modify name char(10) not null;
mysql> select * from tnn;
+----+------+
| id | name |
+----+------+
| 0 | |
+----+------+
1 row in set (0.00 sec)
mysql> select * from tnn where name is null;
Empty set (0.00 sec)
mysql> select * from tnn where name=''; //匹配空字符串
+----+------+
| id | name |
+----+------+
| 0 | |
+----+------+
1 row in set (0.00 sec)
#注意:非空的约束,对于数值型,未指定插入值时,默认会插入0;对于字符串型,未指定插入值时,默认会插入空字符串。
3、唯一 unique
mysql> create table tuni (id int unique,name char(10));
mysql> desc tuni;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id | int(11) | YES | UNI | NULL | |
| name | char(10) | YES | | NULL | |
+-------+----------+------+-----+---------+-------+
mysql> insert into tuni values();
mysql> insert into tuni values(); //注意:唯一性约束对空值无效
mysql> insert into tuni values(1,'tom');
mysql> insert into tuni values(2,'mary');
mysql> insert into tuni values(1,'jack');
ERROR 1062 (23000): Duplicate entry '1' for key 'id'
对于唯一性约束,要么向该字段插入空值,要么就向该字段插入唯一的值。
4、主键 primary key
主键是表中的特殊字段,这个字段能够唯一标识表中的每一条记录。
主键用途:快速定位数据
主键在一张表中最多只能有一个。
主键满足的条件:非空且唯一
primary key = not null + unique
1)使用单个字段做主键
a、在字段后直接指定主键约束
mysql> create table pri (id int primary key,age int,name char(10));
mysql> desc pri;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| age | int(11) | YES | | NULL | |
| name | char(10) | YES | | NULL | |
+-------+----------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> insert into pri(id) values (1);
Query OK, 1 row affected (0.01 sec)
mysql> insert into pri(id) values (1);
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
mysql> insert into pri values();
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> show warnings;
+---------+------+-----------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------+
| Warning | 1364 | Field 'id' doesn't have a default value |
+---------+------+-----------------------------------------+
1 row in set (0.00 sec)
mysql> select * from pri;
+----+------+------+
| id | age | name |
+----+------+------+
| 0 | NULL | NULL |
| 1 | NULL | NULL |
+----+------+------+
2 rows in set (0.00 sec)
mysql> insert into pri values();
ERROR 1062 (23000): Duplicate entry '0' for key 'PRIMARY'
b、整张表的所有字段都定义完成之后再去指定主键
mysql> create table pri1 (id int,name char(10),primary key(id));
mysql> desc pri1;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id | int(11) | NO | PRI | 0 | |
| name | char(10) | YES | | NULL | |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)
2)多个字段联合做主键
mysql> desc mysql.user; //user和host两个字段联合做主键
+------------------------+-----------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+-----------------------------------+------+-----+---------+-------+
| Host | char(60) | NO | PRI | | |
| User | char(16) | NO | PRI | | |
| Password | char(41) | NO | | | |
mysql> select user,host from mysql.user;
+----------+-------------+
| user | host |
+----------+-------------+
| douni | % |
| douni2 | % |
| douwo | % |
| part | % |
| root | 127.0.0.1 |
| allpriv | 172.16.%.% |
| allpriv1 | 172.16.%.% |
| remote | 172.16.42.8 |
| root | ::1 |
| | localhost |
| ni | localhost |
| root | localhost |
| | mysql |
| root | mysql |
+----------+-------------+
14 rows in set (0.05 sec)
注意:联合主键只能在所有字段都定义之后,再去定义主键
mysql> create table pri2 (id int,name char(10),age int,primary key (id,name));
mysql> insert into pri2 values(1,'Tom',22);
Query OK, 1 row affected (0.00 sec)
mysql> insert into pri2 values(1,'Tom',22);
ERROR 1062 (23000): Duplicate entry '1-Tom' for key 'PRIMARY'
mysql> insert into pri2 values(1,'Mary',20);
Query OK, 1 row affected (0.20 sec)
mysql> insert into pri2 values(2,'Tom',20);
Query OK, 1 row affected (0.00 sec)
对一个已经存在的表,如何添加主键?如何删除主键?
添加主键:
alter table score add primary key(sno);
删除主键:
alter table score drop primary key;
5、外键 foreign key
外键:一个表B中的数据依赖于另一张表A的主键列的数据,如果A表中未出现的值,是不能够出现在B表中的
A:父表
B:子表,外键在子表中
主键和外键就像是表之间的粘合剂,能够将多个表关联起来。
创建外键的条件:
1)存储引擎是innodb(是mysql5.5默认的引擎)
2)相关联字段数据类型要一致
3)最好在外键列上建索引
例子:
dept:部门表
emp:员工表
mysql> create table dept (dno int,dname char(10),primary key (dno));
mysql> create table emp (eno int,edno int,ename char(10),index(edno),foreign key (edno) references dept(dno));
向父表中插入数据
mysql> insert into dept values(100,'manager'),(101,'dba'),(102,'hr'),(103,'sa');
向子表中插入数据
mysql> insert into emp values(1,100,'Tom');
mysql> insert into emp values(2,101,'Mary');
mysql> insert into emp values(3,108,'Daji'); //反例:插入父表中不存在的部门号
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`up`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`edno`) REFERENCES `dept` (`dno`))
删除父表中的数据
mysql> select * from dept;
+-----+---------+
| dno | dname |
+-----+---------+
| 100 | manager |
| 101 | dba |
| 102 | hr |
| 103 | sa |
+-----+---------+
mysql> select * from emp;
+------+------+-------+
| eno | edno | ename |
+------+------+-------+
| 1 | 100 | Tom |
| 2 | 101 | Mary |
+------+------+-------+
2 rows in set (0.00 sec)
mysql> delete from dept where dno=102;
mysql> delete from dept where dno=101;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`up`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`edno`) REFERENCES `dept` (`dno`))
以上小实验小结:
1)子表中的数据依赖于父表,不能向子表中插入父表中不存在的值
2)不能删除父表中被子表所依赖的行
如何解决?
on delete cascade 级联删除
on update cascade 级联更新
mysql> drop table emp;
完整的外键创建
mysql> create table emp (eno int,edno int,ename char(10),index(edno),foreign key (edno) references dept(dno) on delete cascade on update cascade);
mysql> insert into emp values(1,100,'Tom');
mysql> insert into emp values(2,101,'Songjiang');
mysql> insert into emp values(5,101,'Likui');
mysql> delete from dept where dno=101;
mysql> select * from dept;
+-----+---------+
| dno | dname |
+-----+---------+
| 100 | manager |
| 103 | sa |
+-----+---------+
2 rows in set (0.00 sec)
mysql> select * from emp;
+------+------+-------+
| eno | edno | ename |
+------+------+-------+
| 1 | 100 | Tom |
+------+------+-------+
1 row in set (0.00 sec)
mysql> update dept set dno=110 where dno=100;
mysql> select * from emp;
+------+------+-------+
| eno | edno | ename |
+------+------+-------+
| 1 | 110 | Tom |
+------+------+-------+
1 row in set (0.00 sec)
有了级联删除和级联修改选项,父表中的数据发生删除或者更新时,子表中的数据也会发生相应的变化。
删除外键
查看外键的名字
mysql> show create table emp\G
*************************** 1. row ***************************
Table: emp
Create Table: CREATE TABLE `emp` (
`eno` int(11) DEFAULT NULL,
`edno` int(11) DEFAULT NULL,
`ename` char(10) DEFAULT NULL,
KEY `edno` (`edno`), //索引
CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`edno`) REFERENCES `dept` (`dno`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> alter table emp drop foreign key emp_ibfk_1;
6、自增 auto_increment
要求:
1)该字段的类型必须是数值型的
2)字段上要有唯一性索引或主键
mysql> create table zz (id int primary key auto_increment);
mysql> desc zz;
+-------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
+-------+---------+------+-----+---------+----------------+
1 row in set (0.00 sec)
mysql> insert into zz values();
Query OK, 1 row affected (0.02 sec)
mysql> select * from zz;
+----+
| id |
+----+
| 1 |
+----+
1 row in set (0.00 sec)
几点说明:
1)当自增字段发生断档时,值从最大值继续自增
mysql> insert into zz values();
Query OK, 1 row affected (0.01 sec)
mysql> select * from zz;
+----+
| id |
+----+
| 1 |
| 2 |
| 5 |
| 6 |
+----+
4 rows in set (0.00 sec)
2)当用delete删除最大值时,下一个值仍然从最大值的下一个继续自增
mysql> delete from zz where id=6;
Query OK, 1 row affected (0.04 sec)
mysql> insert into zz values();
Query OK, 1 row affected (0.00 sec)
mysql> select * from zz;
+----+
| id |
+----+
| 1 |
| 2 |
| 5 |
| 7 |
+----+
4 rows in set (0.00 sec)
3)当你truncate一个表时,值从1开始重新计算
mysql> truncate table zz;
Query OK, 0 rows affected (0.05 sec)
mysql> insert into zz values();
Query OK, 1 row affected (0.00 sec)
mysql> select * from zz;
+----+
| id |
+----+
| 1 |
+----+
1 row in set (0.00 sec)