MySQL表的约束

目录

1.空属性

2.默认值defalut

3.列描述

4.zerofill

5.主键约束

5.1主键

5.2复合主键

6.自增长

7.唯一键

8.外键


为什么要有约束,其实是为了保证数据的合法性,在上一章中我们说到数据类型其实就是一种约束,比如tinyint类型的取值范围是-128-127,如果超过了这个范围,就直接报错,而不是发生c语言中的截断,这样可以倒逼程序员必须插入合法的数据。

1.空属性

  • 两个值:null(默认的)和not null(不为空)
  • 数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办法参与运算。

这里需要区分一下' ' 和 null, mysql中的null表示什么都没有,而' '表示的是空串,其实也是一种数据。

案例:创建一个班级表,包含班级名和班级所在的教室。

站在正常的业务逻辑中:

如果班级没有名字,你不知道你在哪个班级

如果教室名字可以为空,就不知道在哪上课

所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中。这就是“约束”。

mysql> create table myclass(
-> class_name varchar(20) not null,
-> class_room varchar(10) not null
-> );
Query OK, 0 rows affected (0.02 sec)

我们可以看到在null那一列属性当中,就变成了no,也就是不能为空,此时在插入数据时,class_name和class_room就不能为空了。

mysql>  insert into myclass(class_name) values('class1');
ERROR 1364 (HY000): Field 'class_room' doesn't have a default value

mysql>  insert into myclass(class_name, class_room) values('class1', '601');
Query OK, 1 row affected (0.00 sec)

2.默认值defalut

默认值:某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,在需要真实数据的时候,用户可以选择性的使用默认值。

mysql> create table t10(
    -> name varchar(20) not null,
    -> age tinyint unsigned default 18,
    -> gender char(1) default '男'
    -> );
Query OK, 0 rows affected (0.02 sec)

可以看到default属性那一列也发生了变化。

我们再插入一些数据看看。

mysql> insert into t10(name, age, gender) values('张三', 20, '女');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t10(name, gender) values('李四', '男');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t10(name, age) values('王五', 32);
Query OK, 1 row affected (0.00 sec)

mysql> insert into t10(name) values('王五');
Query OK, 1 row affected (0.00 sec)

如果设置了默认值,并且没有填写,使用的就是默认值。

  • 那如果既设置了not null又设置了default呢
mysql> create table t11( 
mysql> name varchar(20) not null,
mysql> age tinyint(4),
mysql> gender char(2) not null default '男'
mysql> );
Query OK, 0 rows affected (0.03 sec)

再插入几个数据试试。

mysql> insert into t11(name, age, gender) values('张三', 12, '男');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t11(name, gender) values('张三', '男');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t11(name) values('张三');
Query OK, 1 row affected (0.00 sec)

  • not null和default是可以同时存在的。
  • 同时存在时,不传也不会出错,因为会使用默认值default。
  • not null和defalut一般不需要同时出现,因为default本身有默认值,不会为空
  • 如果创建表时,没有填not null和default,则默认,default字段默认为null,null字段为yes

3.列描述

列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA来进行了解。

有点像语言中的注释

mysql> create table tt12 (
    -> name varchar(20) not null comment '姓名',
    -> age tinyint unsigned default 0 comment '年龄',
    -> sex char(2) default '男' comment '性别'
    -> );
Query OK, 0 rows affected (0.02 sec)
  • 使用desc无法观察到

  • 需要使用show

4.zerofill

前面在学习数据库的过程当中,我们看到整型类型后面会加一个长度

mysql> show create table tt3\G
***************** 1. row *****************
Table: tt3
Create Table: CREATE TABLE `tt3` (
    `a` int(10) unsigned DEFAULT NULL,
    `b` int(10) unsigned DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=gbk
1 row in set (0.00 sec)

可以看到int(10),这个代表什么意思呢?整型不是4字节码?这个10又代表什么呢?其实没有zerofill这个属性,括号内的数字是毫无意义的。a和b列就是前面插入的数据,如下:

mysql> insert into tt3 values(1,2);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tt3;
+------+------+
| a | b |
+------+------+
| 1 | 2 |
+------+------+

但是对列添加了zerofill属性后,显示的结果就有所不同了。修改tt3表的属性:

mysql> alter table tt3 change a a int(5) unsigned zerofill;
mysql> show create table tt3\G
*************************** 1. row ***************************
Table: tt3
Create Table: CREATE TABLE `tt3` (
`a` int(5) unsigned zerofill DEFAULT NULL, --具有了zerofill
`b` int(10) unsigned DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
mysql> select * from tt3;
+-------+------+
| a     | b    |
+-------+------+
| 00001 | 2    |
+-------+------+

这次可以看到a的值由原来的1变成00001,这就是zerofill属性的作用,如果宽度小于设定的宽度(这里设置的是5),自动填充0。要注意的是,这只是最后显示的结果,在MySQL中实际存储的还是1。

如果括号里面设置的是4,但我们实际的数超过了4位,那就会按数据本身显示。

5.主键约束

5.1主键

主键:primary key用来唯一的约束该字段里面的数据,不能重复,不能为空,一张表中最多只能有一个主键;主键所在的列通常是整数类型

mysql> create table tt13 (
-> id int unsigned primary key comment '学号不能为空',
-> name varchar(20) not null
-> );
Query OK, 0 rows affected (0.00 sec)

mysql> desc tt13;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id    | int(10) unsigned | NO   | PRI | NULL    |       | 
| name  | varchar(20)      | NO   |     | NULL    |       |
+-------+------------------+------+-----+---------+-------+

key中的PRI表示的就是主键,主键是自带非空约束的。

  • 主键约束:主键对应的字段中不能重复,一旦重复,操作失败。
     
mysql> insert into tt13 values(1, 'aaa');
Query OK, 1 row affected (0.00 sec)

mysql> insert into tt13 values(1, 'aaa');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

主键的作用就是为了保证记录的唯一性,比如身份证号,手机号,qq号之类无法重复的数据就可以使用主键。

  • 当表创建好以后但是没有主键的时候,可以再次追加主键
     
alter table 表名 add primary key(字段列表)
  • 删除主键
alter table 表名 drop primary key;

mysql> alter table tt13 drop primary key;
mysql> desc tt13;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id    | int(10) unsigned | NO   |     | NULL    |       |
| name  | varchar(20)      | NO   |     | NULL    |       |
+-------+------------------+------+-----+---------+-------+


5.2复合主键

在创建表的时候,在所有字段之后,使用primary key(主键字段列表)来创建主键,如果有多个字段作为主键,可以使用复合主键

mysql> create table t13(
    -> a int,
    -> b int,
    -> c int,
    -> primary key(a, b)
    -> );
Query OK, 0 rows affected (0.02 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共同构成了一个主键,所以只有a,b完全相同时才会发生冲突,a相同b不相同的情况下是不会构成冲突的。

mysql> insert into t13 values(10, 20, 30);
Query OK, 1 row affected (0.01 sec)

mysql> insert into t13 values(10, 10, 30);
Query OK, 1 row affected (0.01 sec)

mysql> insert into t13 values(20, 20, 30);
Query OK, 1 row affected (0.00 sec)

mysql> insert into t13 values(10, 20, 30);
ERROR 1062 (23000): Duplicate entry '10-20' for key 'PRIMARY'

6.自增长

auto_increment:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值+1操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键。

自增长的特点:

  1. 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)
  2. 自增长字段必须是整数
  3. 一张表最多只能有一个自增长
mysql> create table t14(
    -> a int primary key auto_increment,
    -> b varchar(10) not null
    -> );
Query OK, 0 rows affected (0.02 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)

可以看到Extra属性那里就变成了auto_increnment。

插入几个数据试试。

mysql> insert into t14 values(10, 'hello');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t14 (b) values('hello');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t14 (b) values('hello');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t14 (b) values('hello');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t14 (b) values('hello');
Query OK, 1 row affected (0.01 sec)

当我们第一次显示的给a传值的时候,a就是10,后面我们再没给a值的时候,a就是在上一次插入的基础上继续插入。

这上面的AUTO_INCREMENT就是下次默认插入的值,我们也可以使用last_insert_id()这个函数来获取上一次AUTO_INCREMENT的值。

  • 创建表的时候设置起始增长值
mysql> create table t15(
    -> a int primary key auto_increment,
    -> b varchar(10)
    -> )auto_increment=100;
Query OK, 0 rows affected (0.02 sec)

mysql> insert into t15 (b) values ('hello');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t15 (b) values ('hello');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t15 (b) values ('hello');
Query OK, 1 row affected (0.00 sec)

mysql> select * from t15;
+-----+-------+
| a   | b     |
+-----+-------+
| 100 | hello |
| 101 | hello |
| 102 | hello |
+-----+-------+
3 rows in set (0.00 sec)

7.唯一键

一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键唯一键就可以解决表中有多个字段需要唯一性约束的问题

唯一键的本质和主键差不多,唯一键允许为空,而且可以多个为空,空字段不做唯一性比较。

举个例子,在一个公司当中,我们以员工工号作为主键,但是还有很多其他信息是不能重复的,比如员工的身份证号,手机号,那么我们就可以把身份证号和手机号设置为唯一键。

mysql> create table student(
    -> id char(20) unique,
    -> name varchar(32) not null
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql> desc student;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | char(20)    | YES  | UNI | NULL    |       |
| name  | varchar(32) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

key属性那里就变成了UNI。

mysql> insert into student values ('111', '张三');
Query OK, 1 row affected (0.00 sec)

mysql> insert into student values ('222', '张三');
Query OK, 1 row affected (0.00 sec)

mysql> insert into student (name)  values ('张三');
Query OK, 1 row affected (0.00 sec)

mysql> insert into student values ('111', '张三');
ERROR 1062 (23000): Duplicate entry '111' for key 'id'

mysql> select * from student;
+------+--------+
| id   | name   |
+------+--------+
| 111  | 张三   |
| 222  | 张三   |
| NULL | 张三   |
+------+--------+
3 rows in set (0.00 sec)

唯一键是可以为空的,并且插入了相同的值的时候也会报错。

主键和唯一键并不冲突并且是相互补充的。

主键和唯一键的侧重点:

  • 主键主要是标志了表中某一行的唯一性。
  • 唯一键是保证当前列数据不冲突

8.外键

外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或unique约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为null。

foreign key (字段名) references 主表(列)

先创建主表。

mysql> create table myclass(
    -> id int primary key,
    -> name varchar(30) not null comment'班级名'
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> desc myclass;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(30) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

再创建从表。

mysql> create table stu(
    -> id int primary key,
    -> name varchar(30) not null comment'学生名',
    -> class_id int,
    -> foreign key (class_id) references myclass(id)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> desc stu;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int(11)     | NO   | PRI | NULL    |       |
| name     | varchar(30) | NO   |     | NULL    |       |
| class_id | int(11)     | YES  | MUL | NULL    |       |
+----------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> insert into myclass values(10, 'C++大牛班'),(20, 'java大神班');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> insert into stu values(100, '张三', 10),(101, '李四',20);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql>  insert into stu values(102, 'wangwu',30);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`user5`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `myclass` (`id`))

mysql> insert into stu values(102, 'wangwu', null);
Query OK, 1 row affected (0.00 sec)

第三次插入时,因为主表中的id并不存在30,所以插入失败了

分析:

我们不创建外键约束,就正常建立学生表,以及班级表,该有的字段我们都有。

此时,在实际使用的时候,可能会出现什么问题?

有没有可能插入的学生信息中有具体的班级,但是该班级却没有在班级表中?其实是很有可能的,比如一个程序员粗心了,输入错误导致。因为此时两张表在业务上是有相关性的,但是在业务上没有建立约束关系,那么就可能出现问题。
解决方案就是通过外键完成的。建立外键的本质其实就是把相关性交给mysql去审核了,提前告诉mysql表之间的约束关系,那么当用户插入不符合业务逻辑的数据的时候,mysql不允许你插入。


如果我们想删除主表中的数据呢

mysql> delete from myclass where id = 10;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`user5`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `myclass` (`id`))

直接删除是不行的,因为还有其他从表和他关联着,想要删除,必须把id=10的从表中的数据全部删除。

mysql> select * from stu;
+-----+--------+----------+
| id  | name   | class_id |
+-----+--------+----------+
| 100 | 张三   |       10 |
| 101 | 李四   |       20 |
| 102 | wangwu |     NULL |
+-----+--------+----------+
3 rows in set (0.00 sec)

mysql> delete from stu where class_id = 10;
Query OK, 1 row affected (0.00 sec)

mysql> delete from myclass where id = 10;
Query OK, 1 row affected (0.01 sec)

mysql> select * from myclass;
+----+---------------+
| id | name          |
+----+---------------+
| 20 | java大神班    |
+----+---------------+
1 row in set (0.00 sec)

  • 18
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值