真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。比如有一个字段是email,要求是唯一的。
表的约束很多,这里主要介绍如下几个: null/not null,default, comment, zerofill,primary key,auto_increment,unique key
。
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。
默认值:某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,在需要真实数据的时候,
用户可以选择性的使用默认值。
我们创建一张表,并向里面插入数据
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本身有默认值,不会为空。
默认值的生效:数据在插入的时候不给该字段赋值,就使用默认值。
这个约束在之前我们已经使用过,这里大家再看看就好:
列描述: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)
刚开始学习数据库时,很多人对数字类型后面的长度很迷茫。比如下面:
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补齐,否则就原样输出即可。大家在这里一定要明白一点,格式化输出后的数据本身是不会发生改变的,只是输出形式发生了变化而已。
主键: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'
主键对应的字段中不能重复,一旦重复,操作失败。
上面我们设置了name为主键,所以姓名就不能够冲突,否则就会直接报错。
在设置了主键约束的列在key那一列会显示PRI:
语法:
alter table 表名 add primary key(字段列表);
语法:
alter table 表名 drop primary key;
在创建表的时候,在所有字段之后,使用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'
auto_increment
:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值+1操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键。
自增长的特点:
案例:
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)
一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以
解决表中有多个字段需要唯一性约束的问题。唯一键的本质和主键差不多,唯一键允许为空,而且可多个为空,空字段不做唯一性比较。
关于唯一键和主键的区别:
比如一个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。
语法:
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
有一个商店的数据,记录客户及购物情况,有以下三个表组成:
要求:
参考:
-- 商品
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)
);
总的来说实现起来还是很简单的。