文章目录
1 🍑基本概念🍑
真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。比如有一个字段是email,要求是唯一的。
表的约束很多,这里主要介绍如下几个: null/not null,default, comment, zerofill,primary key,auto_increment,unique key
。
2 🍑空属性🍑
- 两个值:null(默认的)和not null(不为空)
- 数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办法参与运算。
mysql> select null;
+------+
| NULL |
+------+
| NULL |
+------+
1 row in set (0.00 sec)
mysql> select null*3;
+--------+
| null*3 |
+--------+
| NULL |
+--------+
1 row in set (0.00 sec)
所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中。这就是“约束”。
create table myclass(
class_name varchar(20) not null,
class_room varchar(10) not null);
当我们进行插入时:
mysql> insert myclass values('zhangsan','107');
Query OK, 1 row affected (0.00 sec)
mysql> insert myclass values('','107');
Query OK, 1 row affected (0.01 sec)
mysql> insert myclass values(null,'107');
ERROR 1048 (23000): Column 'class_name' cannot be null
mysql> insert myclass class_room values('107');
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'class_room values('107')' at line 1
我们发现设置了not null约束的列是不能够省略的,并且是不能够为null。
3 🍑默认值🍑
默认值:某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,在需要真实数据的时候,
用户可以选择性的使用默认值。
我们创建一张表,并向里面插入数据
mysql> create table test_default(
-> name varchar(20) not null,
-> sex varchar(5) default '男',
-> age tinyint unsigned not null default 18
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into test_default values('zhangsan','男',20);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test_default (name) values('zhangsan');
Query OK, 1 row affected (0.01 sec)
mysql> insert into test_default (name,sex) values('lisi','女');
Query OK, 1 row affected (0.00 sec)
mysql> select *from test_default;
+----------+------+-----+
| name | sex | age |
+----------+------+-----+
| zhangsan | 男 | 20 |
| zhangsan | 男 | 18 |
| lisi | 女 | 18 |
+----------+------+-----+
3 rows in set (0.00 sec)
我们发现加了default
约束的列在插入时可以省略,尽管该列同时有着not null的约束。
not null和defalut一般不需要同时出现,因为default本身有默认值,不会为空。
默认值的生效:数据在插入的时候不给该字段赋值,就使用默认值。
4 🍑列描述🍑
这个约束在之前我们已经使用过,这里大家再看看就好:
列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA
来进行了解。
mysql> create table tt12 (
-> name varchar(20) not null comment '姓名',
-> age tinyint unsigned default 0 comment '年龄',
-> sex char(2) default '男' comment '性别'
-> );
mysql> show create table tt12\G
*************************** 1. row ***************************
Table: tt12
Create Table: CREATE TABLE `tt12` (
`name` varchar(20) NOT NULL COMMENT '姓名',
`age` tinyint(3) unsigned DEFAULT '0' COMMENT '年龄',
`sex` char(2) DEFAULT '男' COMMENT '性别'
) ENGINE=MyISAM DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
5 🍑zerofill🍑
刚开始学习数据库时,很多人对数字类型后面的长度很迷茫。比如下面:
mysql> create table test_zerofill(
-> z1 int,
-> z2 int
-> );
Query OK, 0 rows affected (0.04 sec)
mysql> desc test_zerofill;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| z1 | int(11) | YES | | NULL | |
| z2 | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)
int后面的数字代表着什么意思呀?其实没有zerofill这个属性,括号内的数字是毫无意义的;但是对列添加了zerofill属性后,显示的结果就有所不同了。比如下面我们修改表中z1的属性:
mysql> alter table test_zerofill change z1 z1 int(5) zerofill;
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into test_zerofill values(1,2);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test_zerofill values(10,20);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test_zerofill values(100,200);
Query OK, 1 row affected (0.01 sec)
当我们查看表中结果时:
发现是以这样的形式来给我们呈现的,这个其实有点像C语言格式化输出一样,将数据按照一定的格式显示出来,而增加了zerofill
约束的列会自动用0补齐我们设置的位数,比如上面我们设置的位数为5,当结果位数小于5时就用0补齐,否则就原样输出即可。大家在这里一定要明白一点,格式化输出后的数据本身是不会发生改变的,只是输出形式发生了变化而已。
6 🍑主键🍑
主键:primary key
用来唯一的约束该字段里面的数据,不能重复,不能为空,一张表中最多只能有一个主键;主键所在的列通常是整数类型。
mysql> create table test_primarykey(
-> name varchar(20) not null primary key,
-> height float,
-> weight float
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into test_primarykey values('张三',1.75,50);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test_primarykey values('李四',1.85,60);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test_primarykey values('李四',1.65,45);
ERROR 1062 (23000): Duplicate entry '李四' for key 'PRIMARY'
6.1 🍎主键约束🍎
主键对应的字段中不能重复,一旦重复,操作失败。
上面我们设置了name为主键,所以姓名就不能够冲突,否则就会直接报错。
在设置了主键约束的列在key那一列会显示PRI:
6.2 🍎追加主键🍎
- 当表创建好以后但是没有主键的时候,可以再次追加主键。
语法:
alter table 表名 add primary key(字段列表);
6.3 🍎删除主键🍎
语法:
alter table 表名 drop primary key;
6.4 🍎复合主键🍎
在创建表的时候,在所有字段之后,使用primary key
(主键字段列表)来创建主键,如果有多个字段作为主键,可以使用复合主键。
等等,最开始不是说的主键在一张表中最多只能够有一个的吗?为什么还可以出现多个?这里大家不要混淆了,复合主键的意思是在该表中仍然只有一个主键,但是该主键可能是由多个列复合而成的。
比如下面:
mysql> create table class(
-> id int unsigned,
-> course char(10) comment '课程代码',
-> score tinyint unsigned default 60 comment '成绩',
-> primary key(id, course)
-> );
Query OK, 0 rows affected (0.03 sec)
我们将id和course作为复合主键,只要这两个中有一个没有冲突了就都可以插入成功,只有id和course都冲突的情况下才会插入失败。我们来验证下:
mysql> insert class values(1,'1234',95);
Query OK, 1 row affected (0.00 sec)
mysql> insert class values(2,'1234',95);
Query OK, 1 row affected (0.00 sec)
mysql> insert class values(2,'12354',95);
Query OK, 1 row affected (0.00 sec)
mysql> insert class values(2,'12354',95);
ERROR 1062 (23000): Duplicate entry '2-12354' for key 'PRIMARY'
7 🍑自增长🍑
auto_increment
:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值+1操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键。
自增长的特点:
- 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)
- 自增长字段必须是整数
- 一张表最多只能有一个自增长
案例:
mysql> create table test_increment(
-> id int unsigned primary key auto_increment,
-> name varchar(10) not null default ''
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into test_increment (name) values('a');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test_increment (name) values('b');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test_increment (name) values('c');
Query OK, 1 row affected (0.00 sec)
mysql> select *from test_increment;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+------+
在插入后获取上次插入的 AUTO_INCREMENT 的值(批量插入获取的是第一个值)
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 3 |
+------------------+
1 row in set (0.00 sec)
这里简单提一下索引
索引:
- 在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。
- 索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引以找到特定值,然后顺指针找到包含该值的行。这样可以使对应于表的SQL语句执行得更快,可快速访问数据库表中的特定信息。
8 🍑唯一键🍑
一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以
解决表中有多个字段需要唯一性约束的问题。唯一键的本质和主键差不多,唯一键允许为空,而且可多个为空,空字段不做唯一性比较。
关于唯一键和主键的区别:
- 我们可以简单理解成,主键更多的是标识唯一性的。而唯一键更多的是保证在业务上,不要和别的信息出现重复。
比如一个student,它的id是不能够冲突的,但是它的其他信息比如身份证号,QQ号等其实也是不能够冲突的,这时只使用主键是不行的,我们就得使用唯一键的约束。
mysql> create table test_unique(
-> id int unique comment '可以为空,但是不能冲突',
-> QQ varchar(20) primary key
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into test_unique values(1,'123456');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test_unique values(null,'1234567');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test_unique values(null,'1234567');
ERROR 1062 (23000): Duplicate entry '1234567' for key 'PRIMARY'
我们发现null是可以插进去的,但是冲突的值就不行。
9 🍑外键🍑
外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或唯一键约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为null。
语法:
foreign key (字段名) references 主表(列)
比如下面这种主从关系:
我们可以根据上面的关系来创建主从表:
mysql> create table cla(
-> id int primary key not null,
-> name varchar(20)
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> create table stu(
-> id int primary key not null,
-> name varchar(20),
-> class_id int,
-> foreign key (class_id) references cla(id)
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into cla values(107,'高三1班');
Query OK, 1 row affected (0.00 sec)
mysql> insert into cla values(108,'高三2班');
Query OK, 1 row affected (0.00 sec)
当stu表中按照下面进行插入就会成功:
mysql> insert into stu values(001,'a',107);
Query OK, 1 row affected (0.01 sec)
mysql> insert into stu values(002,'b',108);
Query OK, 1 row affected (0.01 sec)
但是我们试试下面的插入:
mysql> insert into stu values(003,'c',109);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`db2`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `cla` (`id`))
为什么插入失败了呢?原因很简单,因为在主表中我们并没有创建109的班级。
就算此时我们想要干掉cla表也是不被允许的,因为stu中还有学生是从属于cla的:
mysql> drop table cla;
ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails
9 🍑综合案例🍑
有一个商店的数据,记录客户及购物情况,有以下三个表组成:
- 商品goods(商品编号goods_id,商品名goods_name, 单价unitprice, 商品类别category, 供应商provider)
- 客户customer(客户号customer_id,姓名name,住址address,邮箱email,性别sex,身份证card_id)
- 购买purchase(购买订单号order_id,客户号customer_id,商品号goods_id,购买数量nums)
要求:
- 每个表的主外键
- 客户的姓名不能为空值
- 邮箱不能重复
- 客户的性别(男,女)
参考:
-- 商品
create table if not exists goods
(
goods_id int primary key auto_increment comment '商品编号',
goods_name varchar(32) not null comment '商品名称',
unitprice int not null default 0 comment '单价,单位分',
category varchar(12) comment '商品分类',
provider varchar(64) not null comment '供应商名称'
);
-- 客户
create table if not exists customer
(
customer_id int primary key auto_increment comment '客户编号',
name varchar(32) not null comment '客户姓名',
address varchar(256) comment '客户地址',
email varchar(64) unique key comment '电子邮箱',
sex enum('男','女') not null comment '性别',
card_id char(18) unique key comment '身份证'
);
-- 购买
create table if not exists purchase
(
order_id int primary key auto_increment comment '订单号',
customer_id int comment '客户编号',
goods_id int comment '商品编号',
nums int default 0 comment '购买数量',
foreign key (customer_id) references customer(customer_id),
foreign key (goods_id) references goods(goods_id)
);
总的来说实现起来还是很简单的。