一、表的约束
真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。比如有一个字段是email,要求是唯一的。
表的约束很多,这里主要介绍如下几个,其余的以后讲解。null/not null,default, comment, zerofill,primary key,auto_increment,unique。
1.1 空属性
- 两个值:null 和 not null
- 数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办法参与运算。
mysql> select null;
+------+
| NULL |
+------+
| NULL |
+------+
1 row in set (0.00 sec)
mysql> select 1+null;
+--------+
| 1+null |
+--------+
| NULL |
+--------+
1 row in set (0.00 sec)
创建一个班级表,包含班级名和班级所在的教室,如果班级没有名字,你不知道你在哪个班级,如果教室名字可以为空,就不知道在哪上课。
mysql> create table myclass(
-> class_name varchar(20) not null,
-> class_room varchar(10) not null
-> );
Query OK, 0 rows affected (0.06 sec)
mysql> desc myclass;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| class_name | varchar(20) | NO | | NULL | |
| class_room | varchar(10) | NO | | NULL | |
+------------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)
插入数据,如果没有数据就会插入失败:
mysql> insert into myclass(class_name) values('class1');
ERROR 1364 (HY000): Field 'class_room' doesn't have a default value
1.2 默认值
默认值:某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,在需要真实数据的时候,用户可以选择性的使用默认值。
mysql> create table tt12 (
-> name varchar(20) not null,
-> age tinyint unsigned default 0,
-> gender char(2) default '男'
-> );
Query OK, 0 rows affected (0.06 sec)
mysql> desc tt12;
+--------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| age | tinyint(3) unsigned | YES | | 0 | |
| gender | char(2) | YES | | 男 | |
+--------+---------------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
默认值的生效:数据在插入的时候不给该字段赋值,就使用默认值
mysql> insert into tt12(name) value ('zhangsan');
Query OK, 1 row affected (0.01 sec)
mysql> select * from tt12;
+----------+------+--------+
| name | age | gender |
+----------+------+--------+
| zhangsan | 0 | 男 |
+----------+------+--------+
1 row in set (0.00 sec)
注意:set和enum不能设置默认值。
1.3 列描述
列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA来进行了解。
mysql> create table tt13 (
-> name varchar(20) not null comment '姓名',
-> age tinyint unsigned default 0 comment '年龄',
-> gender char(2) default '男' comment '性别'
-> );
Query OK, 0 rows affected (0.08 sec)
通过的 desc 查看不到注释信息:
mysql> desc tt13;
+--------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| age | tinyint(3) unsigned | YES | | 0 | |
| gender | char(2) | YES | | 男 | |
+--------+---------------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
通过 show 查看:
mysql> show create table tt13\G
*************************** 1. row ***************************
Table: tt13
Create Table: CREATE TABLE `tt13` (
`name` varchar(20) NOT NULL COMMENT '姓名',
`age` tinyint(3) unsigned DEFAULT '0' COMMENT '年龄',
`gender` char(2) DEFAULT '男' COMMENT '性别'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
1.4 zerofill
刚开始学习数据库时,很多人对数字类型后面的长度很迷茫。通过 show 看看 tt3 表的建表语句:
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=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.01 sec)
可以看到int(10),这个代表什么意思呢?整型不是4字节码?这个10又代表什么呢?其实没有zerofill这个属性,括号内的数字是毫无意义的。a和b列就是前面插入的数据,如下:
mysql> select * from tt3;
+------+------+
| a | b |
+------+------+
| 1 | 2 |
+------+------+
1 row in set (0.00 sec)
但是对列添加了zerofill属性后,显示的结果就有所不同了。修改tt3表的属性:
mysql> alter table tt3 change a a int(5) unsigned zerofill;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
对a列添加了zerofill属性,再进行查找,返回如下结果:
mysql> select * from tt3;
+-------+------+
| a | b |
+-------+------+
| 00001 | 2 |
+-------+------+
1 row in set (0.00 sec)
这次可以看到a的值由原来的1变成00001,这就是zerofill属性的作用,如果宽度小于设定的宽度(这里设置的是5),自动填充0。要注意的是,这只是最后显示的结果,在MySQL中实际存储的还是1。为什么是这样呢?我们可以用hex函数来证明。
mysql> select a, hex(a) from tt3;
+-------+--------+
| a | hex(a) |
+-------+--------+
| 00001 | 1 |
+-------+--------+
1 row in set (0.01 sec)
可以看出数据库内部存储的还是1,00001只是设置了zerofill属性后的一种格式化输出而已。
1.5 主键
主键:primary key用来唯一的约束该字段里面的数据,不能重复,不能为空,主键所在的列是整数类型。
一张表中最多只能有一个主键。
创建表的时候直接在字段上指定主键:
mysql> create table tt14 (
-> id int unsigned primary key comment '学号不能为空',
-> name varchar(20) not null
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> desc tt14;
+-------+------------------+------+-----+---------+-------+
| 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 tt15 (
-> id int unsigned,
-> course char(10) comment '课程代码',
-> score tinyint unsigned default 60 comment '成绩',
-> primary key(id, course) -- id和course为复合主键
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> desc tt15;
+--------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | NULL | |
| course | char(10) | NO | PRI | NULL | |
| score | tinyint(3) unsigned | YES | | 60 | |
+--------+---------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
当表创建好以后,可以再次追加主键
alter table 表名add primary key(字段列表)
主键约束:主键对应的字段中不能重复,一旦重复,操作失败。
mysql> insert into tt14 values (1, 'aaa');
Query OK, 1 row affected (0.00 sec)
mysql> insert into tt14 values (1, 'aaa');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
删除主键:
alter table 表名drop primary key;
mysql> alter table tt14 drop primary key;
Query OK, 1 row affected (0.06 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> desc tt14;
+-------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | | NULL | |
| name | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
1.6 自增长
auto_increment:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值+1操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键。
自增长的特点:
- 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)
- 自增长字段必须是整数
- 一张表最多只能有一个自增长
示例:
mysql> create table tt16 (
-> id int unsigned primary key auto_increment,
-> name varchar(10) not null default ''
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into tt16(name) values('a');
Query OK, 1 row affected (0.01 sec)
mysql> insert into tt16(name) values('b');
Query OK, 1 row affected (0.00 sec)
mysql> select * from tt16;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
+----+------+
2 rows in set (0.00 sec)
1.7 唯一键
一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以解决表中有多个字段需要唯一性约束的问题。
- 唯一键的本质和主键差不多,唯一键允许为空,而且可以多个为空,空字段不做唯一性比较。
mysql> create table student (
-> id char(10) unique comment '学号,不能重复,但可以为空',
-> name varchar(10)
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into student (id, name) values('01', 'aaa');
Query OK, 1 row affected (0.01 sec)
mysql> insert into student(id, name) values('01', 'bbb'); -- 唯一约束不能重复
ERROR 1062 (23000): Duplicate entry '01' for key 'id'
mysql> insert into student(id, name) values(null, 'bbb'); -- 但可以为空
Query OK, 1 row affected (0.00 sec)
mysql> select * from student;
+------+------+
| id | name |
+------+------+
| 01 | aaa |
| NULL | bbb |
+------+------+
2 rows in set (0.00 sec)
二、表的增删改查(CRUD)详解
2.1 增加
语法:
insert into table_name[(column[,column...])] values (value [,value...]);
示例:
1.创建一张商品表:
mysql> create table goods(
-> id int unsigned primary key,
-> goods_name varchar(50) not null default'',
-> price float not null default 0.0
-> );
Query OK, 0 rows affected (0.03 sec)
2.插入两条记录:
mysql> insert into goods values(100, '牛排', 88.8);
Query OK, 1 row affected (0.01 sec)
mysql> insert into goods values(101, '披萨', 25.8);
Query OK, 1 row affected (0.00 sec)
mysql> select * from goods;
+-----+------------+-------+
| id | goods_name | price |
+-----+------------+-------+
| 100 | 牛排 | 88.8 |
| 101 | 披萨 | 25.8 |
+-----+------------+-------+
2 rows in set (0.00 sec)
使用添加语句注意的细节:
- 插入的数据应与字段的数据类型相同。比如,将‘abc’插入到id列就不行:
mysql> insert into goods values('abc', 'pizza', 72);
ERROR 1366 (HY000): Incorrect integer value: 'abc' for column 'id' at row 1
- 数据的大小应在规定的范围内,例如:不能将一个长度为80的字符串插入到长度为40的列中。
mysql> create table tt17(name varchar(5));
Query OK, 0 rows affected (0.03 sec)
mysql> insert into tt17 values('abcdef');
ERROR 1406 (22001): Data too long for column 'name' at row 1
- 在values中列出的数据位置必须与被加入的列位置相对应。
mysql> insert into goods values(200, 3.4, 'steak'); --价格和名字写反了
ERROR 1265 (01000): Data truncated for column 'price' at row 1
- 字符和日期类型应该包含在单引号中。
mysql> insert into goods values(123, fish, 50); --字符串没有用单引号
ERROR 1054 (42S22): Unknown column 'fish' in 'field list'
- 插入空值,不指定或 insert into table values(null)
- insert into table values(),(),() 一次性添加多条记录
mysql> insert into goods values(1, 'aa', 3.3), (2, 'bb', 4.4),(3, 'cc', 5.5); -- 一次性添加三条记录
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from goods;
+-----+------------+-------+
| id | goods_name | price |
+-----+------------+-------+
| 1 | aa | 3.3 |
| 2 | bb | 4.4 |
| 3 | cc | 5.5 |
+-----+------------+-------+
3 rows in set (0.00 sec)
- 如果给表中的所有字段添加数据,可以不写前面的字段名称
mysql> insert into goods values(4, 'apple', 3.5); -- 如果没有给出字段名称,values中必须给出所有的字段值
Query OK, 1 row affected (0.00 sec)
- 如果你只给表的某几个字段赋值,则需要制定字段名
mysql> insert into goods(id, goods_name) values (5, 'mouse');
Query OK, 1 row affected (0.01 sec)
2.1.1 增加进阶
在数据插入的时候,假设主键对应的值已经存在:插入失败!
mysql> insert into goods values(101, 'ccc', 20.5);
ERROR 1062 (23000): Duplicate entry '101' for key 'PRIMARY'
当主键存在冲突的时候(duplicate key),可以选择性的进行处理:
1.更新操作:
insert into 表名(字段列表) values(值列表) on duplicate key update 字段=新值;
mysql> insert into goods values(101, 'ccc', 20.5) on duplicate key update goods_name='ccc',
price=20.5;
Query OK, 2 rows affected (0.01 sec)
2.替换:主键如果没有冲突,就直接插入
replace into 表名(包含字段) values(值列表);
mysql> replace into goods values(100, 'huawei', 1999);
Query OK, 2 rows affected (0.01 sec)
mysql> select * from goods;
+-----+------------+-------+
| id | goods_name | price |
+-----+------------+-------+
| 1 | aa | 3.3 |
| 2 | bb | 4.4 |
| 3 | cc | 5.5 |
| 4 | apple | 3.5 |
| 5 | mouse | 0 |
| 100 | huawei | 1999 |
| 101 | ccc | 20.5 |
+-----+------------+-------+
7 rows in set (0.00 sec)
2.2 修改
更新表中的数据
语法:
update tbl_name set col_name1=expr1, [, col_name2=expr2 ...] [where conditon]
示例:将所有产品的价格修改为300
mysql> update goods set price=300;
Query OK, 7 rows affected (0.01 sec)
Rows matched: 7 Changed: 7 Warnings: 0
mysql> select * from goods;
+-----+------------+-------+
| id | goods_name | price |
+-----+------------+-------+
| 1 | aa | 300 |
| 2 | bb | 300 |
| 3 | cc | 300 |
| 4 | apple | 300 |
| 5 | mouse | 300 |
| 100 | huawei | 300 |
| 101 | ccc | 300 |
+-----+------------+-------+
7 rows in set (0.00 sec)
示例:将 id 为 100 的产品价格修改为2000:
mysql> update goods set price=2000 where id=100;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from goods where id=100;
+-----+------------+-------+
| id | goods_name | price |
+-----+------------+-------+
| 100 | huawei | 2000 |
+-----+------------+-------+
1 row in set (0.00 sec)
示例:将 id 为 101 的产品价格增加200:
mysql> update goods set price=price+200 where id=101;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from goods where id=101;
+-----+------------+-------+
| id | goods_name | price |
+-----+------------+-------+
| 101 | ccc | 500 |
+-----+------------+-------+
1 row in set (0.00 sec)
update 使用细节:
- update 语法可以用心值更新原有表中的各列
- set子句指示要修改哪些列和要给予哪些值
- where子句指定应更新哪些行。如果没有where子句,则更新所有行
- 如果需要更新多个字段,可以通过set 字段1=值1,字段2=值2…
更新还可以限制更新数量:
update 表名set 字段=值[where 条件] [limit 更新数量];
比如,goods表中有5条ccc产品。我们希望将前3条改成ddd:
mysql> select * from goods where goods_name='ccc';
+-----+------------+-------+
| id | goods_name | price |
+-----+------------+-------+
| 101 | ccc | 500 |
| 102 | ccc | 999 |
| 103 | ccc | 999 |
| 104 | ccc | 999 |
| 105 | ccc | 999 |
+-----+------------+-------+
5 rows in set (0.00 sec)
执行更新操作并查询结果:
mysql> update goods set goods_name='ddd' where goods_name='ccc' limit 3;
Query OK, 3 rows affected (0.01 sec)
Rows matched: 3 Changed: 3 Warnings: 0
mysql> select * from goods;
+-----+------------+-------+
| id | goods_name | price |
+-----+------------+-------+
| 1 | aa | 300 |
| 2 | bb | 300 |
| 3 | cc | 300 |
| 4 | apple | 300 |
| 5 | mouse | 300 |
| 100 | huawei | 2000 |
| 101 | ddd | 500 |
| 102 | ddd | 999 |
| 103 | ddd | 999 |
| 104 | ccc | 999 |
| 105 | ccc | 999 |
+-----+------------+-------+
11 rows in set (0.00 sec)
2.3 删除
删除表中的数据
语法:
delete from tbl_name [where condition]
示例:删除表中 id 为 101 的数据
mysql> delete from goods where id=101;
Query OK, 1 row affected (0.01 sec)
在练习删除时,可以复制一份表,避免数据删没了
1.复制表结构:
mysql> create table goods2 like goods;
Query OK, 0 rows affected (0.06 sec)
2.把 goods 表的数据复制到 goods2:
mysql> insert into goods2 select * from goods;
Query OK, 10 rows affected (0.01 sec)
Records: 10 Duplicates: 0 Warnings: 0
删除表中的所有记录:
mysql> delete from goods; --删除整个表的数据,但是表的结构还存在
使用truncate删除表中的记录:
mysql> truncate table goods; --这个指令也把整个表记录删除
上述两种删除整表的区别:
- 效果一样,truncate速度快
- delete可以带where条件,删除更加灵活
- delete可以返回被删除的记录数,而truncate返回0
- 推荐使用delete
delete使用细节:
- 如果不适用where子句,将删除整个表中所有数据
- delete语句不能删除某一列的值(可以用update置null)
- 使用delete语句仅删除记录,不删除表本身(drop table)