约束是为了更好的保证数据的合法性,如果没有约束,我们可能在年龄字段填写个男,在性别字段填写个18。
通过约束,倒逼程序员插入数据库表中的数据符合预期。
两个值:null(默认的)和not null(不为空)
数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办法参与运算。
MySQL中的NULL代表什么都没有。
MySQL中的''
代表空串
我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中。这就是“约束”。
mysql> create table if not exists myclass(
-> class_name varchar(20) not null,
-> class_room varchar(20) not null,
-> other varchar(20)
-> );
Query OK, 0 rows affected (0.04 sec)
这就表示插入的时候class_name
和class_room
不能为空。
mysql> insert into myclass (class_name, class_room, other) values('大一', '101', '普通');
Query OK, 1 row affected (0.00 sec)
mysql> insert into myclass (class_name, class_room) values('大二', '102');
Query OK, 1 row affected (0.01 sec)
mysql> insert into myclass (class_name) values('大三');
ERROR 1364 (HY000): Field 'class_room' doesn't have a default value
mysql> insert into myclass (class_name) values('大三', NULL);
ERROR 1136 (21S01): Column count doesn't match value count at row 1
默认值:某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,在需要真实数据的时候,用户可以选择性的使用默认值。
创建表:
mysql> create table t9(
-> name varchar(20) not null,
-> age tinyint unsigned default 18,
-> gender char(1) default '男'
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into t9 (name) values ('张三');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t9;
+--------+------+--------+
| name | age | gender |
+--------+------+--------+
| 张三 | 18 | 男 |
+--------+------+--------+
1 row in set (0.00 sec)
可以看到如果设置了默认值并且没填写,默认为设置的default值。
当然如果设置了not noll并且没有设置default并且没有插入数据就会报错。
mysql> create table t10(
-> name varchar(20) not null,
-> age tinyint(4),
-> gender char(1) not null default '男'
-> );
Query OK, 0 rows affected (0.04 sec)
可以看到不冲突,可以理解为既然有了缺省值那么一定不会为NULL。
mysql> insert into t10 (name, age) values('李四', 20);
Query OK, 1 row affected (0.01 sec)
mysql> insert into t10 (name) values('李四');
Query OK, 1 row affected (0.00 sec)
not null和defalut一般不需要同时出现,因为default本身有默认值,不会为空
如果我们在创建表的时候没有对字段设置为not null,也没有设置为default,那么该字段默认default null。
列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA来进行了解。
类似于我们平时写的注释。
mysql> create table t11(
-> name varchar(20) not null comment '用户名'
-> );
Query OK, 0 rows affected (0.04 sec)
整型字段有个zerofill属性,在数字长度不够的数据前面填充0,以达到设定的长度。
mysql> create table t12(
-> a int not null,
-> b int unsigned not null
-> );
Query OK, 0 rows affected (0.04 sec)
有符号int圆括号中的数字为11,无符号int圆括号中的数字为10。这是因为有符号int其中一位是符号位。
插入数据:
mysql> insert into t12 values (1, 2);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t12;
+---+---+
| a | b |
+---+---+
| 1 | 2 |
+---+---+
1 row in set (0.00 sec)
此时添加zerofill属性:
mysql> alter table t12 modify b int unsigned zerofill;
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> select * from t12;
+---+------------+
| a | b |
+---+------------+
| 1 | 0000000002 |
+---+------------+
1 row in set (0.00 sec)
再次插入数据:
mysql> insert into t12 values (100, 200);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t12;
+-----+------------+
| a | b |
+-----+------------+
| 1 | 0000000002 |
| 100 | 0000000200 |
+-----+------------+
2 rows in set (0.00 sec)
如果int后边的圆括号是10并且设置了zerofill属性,那么一定会补齐到10位。
这样该列就是等宽的。
比如现在有200个班级,编号从001-200开始,那么创建表时将字段设置为int(3) unsigned或者int(4)就行了。
所以可以看出zerofill的作用就是格式化输出。
还有一点要注意如果括号里面设置的是4,但是位数超过了4位并且设置了zerofill属性那么就会按照数据本身显示。
主键(primary key):用来唯一的约束该字段里面的数据,不能重复,不能为空,一张表中最多只能有一个主键;主键所在的列通常是整数类型。例如学校中的学号,具有唯一性。
mysql> create table test_key(
-> id int unsigned primary key comment '学号',
-> name varchar (20) not null
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> desc test_key;
+-------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | NULL | |
| name | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
可以看到主键自动携带非空约束。
mysql> insert into test_key values (1, '张三');
Query OK, 1 row affected (0.01 sec)
mysql> insert into test_key values (2, '张三');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test_key values (1, '李四');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
主键的作用就是保证了记录的唯一性。
mysql> select * from test_key where id=1;
+----+--------+
| id | name |
+----+--------+
| 1 | 张三 |
+----+--------+
1 row in set (0.01 sec)
mysql> alter table test_key drop primary key;
Query OK, 2 rows affected (0.11 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> desc test_key;
+-------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | | NULL | |
| name | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> alter table test_key add primary key(id);
Query OK, 0 rows affected (0.10 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc test_key;
+-------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | NULL | |
| name | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
在创建表的时候,在所有字段之后,使用primary key(主键字段列表)来创建主键,如果有多个字段作为主键,可以使用复合主键。
mysql> create table t13(
-> a int,
-> b int,
-> c int,
-> primary key(a,b)
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> desc t13;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| a | int(11) | NO | PRI | NULL | |
| b | int(11) | NO | PRI | NULL | |
| c | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
这个表还是只有一个主键,之不过a和b共同构成了一个主键。
mysql> insert into t13 values (1, 2, 3);
Query OK, 1 row affected (0.01 sec)
mysql> insert into t13 values (1, 1, 3);
Query OK, 1 row affected (0.01 sec)
mysql> insert into t13 values (2, 2, 3);
Query OK, 1 row affected (0.00 sec)
mysql> insert into t13 values (1, 2, 4);
ERROR 1062 (23000): Duplicate entry '1-2' for key 'PRIMARY'
这里a和b不能完全一样。也就是只有a和b同时和历史数据冲突了才会出现主键冲突。
auto_increment:每次插入新数据的时候,被设置为自增长的字段的值每次会+1。通常和主键搭配使用,作为逻辑主键。
自增长的特点:
mysql> create table t14(
-> a int primary key auto_increment,
-> b varchar(10) not null
-> );
Query OK, 0 rows affected (0.04 sec)
mysql> desc t14;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| a | int(11) | NO | PRI | NULL | auto_increment |
| b | varchar(10) | NO | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> insert into t14 (b) values ('good');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t14 (b) values ('yes');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t14 (b) values ('hello');
Query OK, 1 row affected (0.01 sec)
mysql> select * from t14;
+---+-------+
| a | b |
+---+-------+
| 1 | good |
| 2 | yes |
| 3 | hello |
+---+-------+
3 rows in set (0.00 sec)
可以看到我们并没有插入数据a,而a默认从1开始自增。
而如果指明插入a:
mysql> insert into t14 (a, b) values (100, 'hello');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t14 (b) values ('hello');
Query OK, 1 row affected (0.01 sec)
mysql> select * from t14;
+-----+-------+
| a | b |
+-----+-------+
| 1 | good |
| 2 | yes |
| 3 | hello |
| 100 | hello |
| 101 | hello |
+-----+-------+
5 rows in set (0.00 sec)
如果手动设置了a(比历史值大),那么就从手动设置的位置开始自增。
创建表,并将自增长值初始值设置为100
mysql> create table t15(
-> a int primary key auto_increment,
-> b varchar(10)
-> )auto_increment=100;
Query OK, 0 rows affected (0.03 sec)
连续插入数据:
mysql> insert into t15 (b) values ('good');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t15 (b) values ('mysql');
Query OK, 1 row affected (0.01 sec)
mysql> select * from t15;
+-----+-------+
| a | b |
+-----+-------+
| 100 | good |
| 101 | mysql |
+-----+-------+
2 rows in set (0.00 sec)
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 101 |
+------------------+
1 row in set (0.00 sec)
一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以解决表中有多个字段需要唯一性约束的问题。一张表中主键只能有一个,但是唯一键可以有多个。
唯一键的本质和主键差不多,唯一键允许为空,而且可以有多个null,空字段不做唯一性比较。
mysql> create table stu(
-> id char(20) unique comment '这是一个学生的唯一键',
-> name varchar(32) not null
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> desc stu;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | char(20) | YES | UNI | NULL | |
| name | varchar(32) | NO | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
插入相同id的数据:
mysql> insert into stu (id, name) values ('111', '张三');
Query OK, 1 row affected (0.01 sec)
mysql> insert into stu (id, name) values ('111', '李四');
ERROR 1062 (23000): Duplicate entry '111' for key 'id'
可以看到不能插入相同的id值。
mysql> insert into stu (id, name) values (NULL, '李四');
Query OK, 1 row affected (0.00 sec)
mysql> insert into stu (id, name) values (NULL, '李四');
Query OK, 1 row affected (0.02 sec)
mysql> insert into stu (id, name) values (NULL, '李四');
Query OK, 1 row affected (0.01 sec)
mysql> select * from stu;
+------+--------+
| id | name |
+------+--------+
| 111 | 张三 |
| NULL | 李四 |
| NULL | 李四 |
| NULL | 李四 |
+------+--------+
4 rows in set (0.00 sec)
唯一键和主键一样,不能重复。但是可以有多个NULL。
主键和唯一键并不冲突而且是相互补充的。
举个例子:
我们把学号作为主键,但是每一行的信息还包括电话号码,不同的学号对应的电话号码不肯能一样,此时我们就可以在电话号码列添加唯一键。
主键和唯一键侧重点不同:
主键主要是保证表中一行的唯一性,而唯一键则是保证当前列的数据不会冲突。
mysql> create table student(
-> id char(20) primary key,
-> name varchar(20) not null,
-> tel char(20) unique key
-> );
Query OK, 0 rows affected (0.06 sec)
插入数据:
mysql> insert into student values ('111', '张三', '12345');
Query OK, 1 row affected (0.00 sec)
mysql> insert into student values ('112', '李四', '12345');
ERROR 1062 (23000): Duplicate entry '12345' for key 'tel'
唯一键加上非空约束后,就和主键的作用一样了。但是记住,他们俩的侧重点不同,主键修饰非业务字段,而唯一键修饰业务字段,均保证字段的唯一性。
外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或unique约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为null。
mysql> create table student(
-> id int unsigned primary key auto_increment,
-> name varchar(20) not null,
-> tel varchar(20) not null,
-> class_id int
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> create table class(
-> id int primary key,
-> name varchar(32) not null
-> );
Query OK, 0 rows affected (0.02 sec)
插入数据:
#插入班级数据
mysql> insert into class values (1, '一班');
Query OK, 1 row affected (0.01 sec)
mysql> insert into class values (2, '二班');
Query OK, 1 row affected (0.01 sec)
#插入学生数据
mysql> insert into student (name, tel, class_id) values ('张三', '123456', 1);
Query OK, 1 row affected (0.00 sec)
mysql> insert into student (name, tel, class_id) values ('李四', '133425', 2);
Query OK, 1 row affected (0.01 sec)
mysql> insert into student (name, tel, class_id) values ('王五', '155499', 2);
Query OK, 1 row affected (0.02 sec)
查看:
mysql> select * from student;
+----+--------+--------+----------+
| id | name | tel | class_id |
+----+--------+--------+----------+
| 1 | 张三 | 123456 | 1 |
| 2 | 李四 | 133425 | 2 |
| 4 | 王五 | 155499 | 2 |
+----+--------+--------+----------+
3 rows in set (0.00 sec)
mysql> select * from class;
+----+--------+
| id | name |
+----+--------+
| 1 | 一班 |
| 2 | 二班 |
+----+--------+
2 rows in set (0.00 sec)
这里的学生表就是教室表的从表,教室是主表。
学生表里的class_id就对应了教室表中的id字段。
可以看到这里的教室一共就两个,但是程序员插入学生信息的时候可能会填成3班
还有一种情况就是删除了其中的一个班级,学生表中的班级就不存在了。
所以mysql就需要外键约束。
现在我们想要插入学生的时候如果班级不存在就不允许插入。
foreign key (从表字段名) references 主表(列)
mysql> create table student(
-> id int unsigned primary key,
-> name varchar(20) not null,
-> tel varchar(20) unique key,
-> class_id int,
-> foreign key(class_id) references class (id)
-> );
mysql> insert into student values(1, '张三', '110', 1);
Query OK, 1 row affected (0.01 sec)
mysql> insert into student values(2, '李四', '120', 2);
Query OK, 1 row affected (0.00 sec)
mysql> insert into student values(3, '王五', '130', 3);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test_db`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))
建立外键的本质其实就是把相关性交给MySQL去审核了,提前告诉MySQL表之间的约束关系,那么当用户插入不符合业务逻辑的数据的时候,MySQL不允许你插入。
mysql> select * from student;
+----+--------+------+----------+
| id | name | tel | class_id |
+----+--------+------+----------+
| 1 | 张三 | 110 | 1 |
| 2 | 李四 | 120 | 2 |
+----+--------+------+----------+
2 rows in set (0.00 sec)
mysql> delete from class where id=1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test_db`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))
因为主表的主键列被其他的从表关联着,所以无法删除。
只有把从表的相关联的数据删除掉后才能删除主表的数据。