前言
-
DML(Data Manipulation Language)语句:数据操纵语句,用于添加、删除、更新和查询数据库记录,并检查数据完整性。常用的语句关键字主要包括 insert、delete、update 和 select 等。
-
常用约束类型
约束类型 解释 not null 非空约束,设定的内容在添加数据的时候不能是 null 的 unique 唯一约束,值是唯一的 primary key 主键约束,非空唯一 auto_increment 主键自增约束,主键为数值型 foreign key 外键约束,B 表使用 A 表的主键 -
常用 where 查询条件
where 条件 解释 > < <= >= <> 大于、小于、大于(小于)等于、不等于 between...and... 在某一区间,闭区间,效果同 and in(set) 在 in 列表中的值,如 in(100, 200),效果同 or like 通配符 模糊查询:% 匹配多个字符,如 first_name like "a%";_ 匹配一个字符,如 first_name like "a_"。 is null 为空 is not null 不为空 and 同时成立 or 任一成立 not 不成立,如 where not(salary > 100); -
常用聚合查询条件
统计函数 解释 count() 求总数 avg() 求平均数 sum() 求和 max() 求最大值 min() 求最小值
1、DML 插入记录语句
-
含可空字段、非空但是含有默认值的字段、自增字段,可以不用在 insert 后的字段列表里面出现,values 后面只写对应字段名称的 value,这些没有写的字段可以自动设置为 NULL、默认值、自增的下一个数字。
-
1)插入单条记录
# 插入单条记录,插入到指定列 # insert into 表名 (列名1, 列名2, ...) values (值1, 值2, ...); > insert into student (name, age, class) values ("xiao bai", 18, "one"); Query OK, 1 row affected (0.09 sec)
# 插入单条记录,插入到所有列 # insert into 表名 values (值1, 值2, ...); > insert into student values (2, "li si", 20, 90, "two", "aaaaaaaa"); Query OK, 1 row affected (0.04 sec)
-
2)插入多条记录
# 插入多条记录,插入到指定列 # insert into 表名 (列名1, 列名2, ...) values (值1, 值2, ...), (值1, 值2, ...), ...; > insert into student (name, age, class) values ("zhang san", 18, "one"), ("li si", 19, "one"); Query OK, 2 rows affected (0.03 sec) Records: 2 Duplicates: 0 Warnings: 0
# 插入多条记录,插入到所有列 # insert into 表名 values (值1, 值2, ...), (值1, 值2, ...), ...; > insert into student values (5, "zhang san", 20, 90, "two", "aaaaaaaa"), (6, "li si", 21, 92, "two", "bbbbbbbb"); Query OK, 2 rows affected (0.08 sec) Records: 2 Duplicates: 0 Warnings: 0
2、DML 删除记录语句
-
delete 一条一条删除,不清空 auto_increment 记录数,truncate 直接将表删除重建表,清空 auto_increment 记录数。
-
不论时单表还是多表,不加 where 条件将会把表的所有记录删除。
-
1)删除单个表中的记录
# 删除单个表中的记录,删除所有表记录 # delete from 表名; > delete from student; Query OK, 5 rows affected (0.08 sec)
# 删除单个表中的记录,删除满足条件的表记录 # delete from 表名 where 条件; > delete from student where no = 5; Query OK, 1 row affected (0.11 sec)
# 删除单个表中的记录,删除所有表记录 # truncate table 表名; > truncate table student; Query OK, 0 rows affected (0.08 sec)
-
2)删除多个表中的记录
# 删除多个表中的记录,如果 from 后面的表用别名,delete 后面也要用相应的别名 # delete 表名1, 表名2, ... from 表名1, 表名2, ... [where 条件]; > delete a, b from emp a, dept b where a.dept.no = b.deptno and a.deptno = 3; Query OK, 2 rows affected (0.04 sec)
3、DML 更新记录语句
-
1)更新单个表中的记录
# 更新单个表中的记录,所有指定列记录 # update 表名 set 字段名 = 值, 字段名 = 值; > update student set age = 18; Query OK, 4 rows affected (0.02 sec) Rows matched: 6 Changed: 4 Warnings: 0
# 更新单个表中的记录,满足条件的指定列记录 # update 表名 set 字段名 = 值, 字段名 = 值 where 条件; > update student set age = 19 where class = "two"; Query OK, 3 rows affected (0.02 sec) Rows matched: 3 Changed: 3 Warnings: 0
-
2)更新多个表中的记录
# 更新多个表中的记录 # update 表名1, 表名2, ... set 表名1.字段名1 = 值, 表名1.字段名2 = 值, 表名2.字段名1 = 值, 表名2.字段名2 = 值, ... [where 条件]; > update emp a, dept b set a.sal = a.sal * b.deptno, b.deptname = a.ename where a.deptno = b.deptno; Query OK, 3 rows affected (0.04 sec) Rows matched: 5 Changed: 3 Warnings: 0
- 多表的更新语法更多的用在根据一个表的字段来动态的更新另外一个表的字段。
4、DML 查询记录语句
4.1 查询单表记录
-
1)简单查询
# 查询单表记录,查询所有数据 # select * from 表名; > select * from zhangwu; +----+-----------------+-------+ | id | name | money | +----+-----------------+-------+ | 1 | chifanzhichu | 247 | | 2 | gongzishouru | 12345 | | 3 | fuzhuangzhichu | 1000 | | 4 | chifanzhichu | 325 | | 5 | gupiaoshouru | 8000 | | 6 | damajiangzhichu | 8000 | | 7 | NULL | 5000 | +----+-----------------+-------+ 7 rows in set (0.00 sec)
# 查询单表记录,查询指定字段记录 # select 字段1, 字段2, ... from 表名; > select id, name from zhangwu; +----+-----------------+ | id | name | +----+-----------------+ | 1 | chifanzhichu | | 2 | gongzishouru | | 3 | fuzhuangzhichu | | 4 | chifanzhichu | | 5 | gupiaoshouru | | 6 | damajiangzhichu | | 7 | NULL | +----+-----------------+ 7 rows in set (0.00 sec)
-
2)去重查询
# 查询单表记录,去除重复记录 # select distinct 字段名 from 表名; > select distinct money from zhangwu; +-------+ | money | +-------+ | 247 | | 12345 | | 1000 | | 325 | | 8000 | | 5000 | +-------+ 6 rows in set (0.00 sec)
-
3)条件查询
# 查询单表记录,查询所有满足条件的记录 # select * from 表名 where 条件; > select * from zhangwu where money >= 8000; +----+-----------------+-------+ | id | name | money | +----+-----------------+-------+ | 2 | gongzishouru | 12345 | | 5 | gupiaoshouru | 8000 | | 6 | damajiangzhichu | 8000 | +----+-----------------+-------+ 3 rows in set (0.00 sec)
-
4)别名查询
- 使用 as 关键字标示别名,可省略。
# 查询单表记录,表别名查询 # select 字段名 from 表名 [as] 别名; > select name from zhangwu as zw; +-----------------+ | name | +-----------------+ | chifanzhichu | | gongzishouru | | fuzhuangzhichu | | chifanzhichu | | gupiaoshouru | | damajiangzhichu | | NULL | +-----------------+ 7 rows in set (0.00 sec)
# 查询单表记录,列别名查询 # select 字段名 [as] 别名 from 表名; > select name as na from zhangwu; +-----------------+ | na | +-----------------+ | chifanzhichu | | gongzishouru | | fuzhuangzhichu | | chifanzhichu | | gupiaoshouru | | damajiangzhichu | | NULL | +-----------------+ 7 rows in set (0.00 sec)
-
5)列运算查询
- 可以直接对列查询的结果进行运算。
# 查询单表记录,列运算查询 # select 字段名(列运算) from 表名; > select money + 10000 from zhangwu; +---------------+ | money + 10000 | +---------------+ | 10247 | | 22345 | | 11000 | | 10325 | | 18000 | | 18000 | | 15000 | +---------------+ 7 rows in set (0.00 sec)
-
6)排序查询
- 排序方式:asc 升序(默认,可省略),desc 降序,排序需放在 where 条件之后。
# 查询单表记录,单列排序查询 # select 字段名 from 表名 [where 条件] order by 列名 排序方式; > select * from zhangwu where money > 1000 order by money asc; +----+-----------------+-------+ | id | name | money | +----+-----------------+-------+ | 7 | NULL | 5000 | | 5 | gupiaoshouru | 8000 | | 6 | damajiangzhichu | 8000 | | 2 | gongzishouru | 12345 | +----+-----------------+-------+ 4 rows in set (0.00 sec)
# 查询单表记录,多列排序查询 # select 字段名 from 表名 [where 条件] order by 列名 排序方式, 列名 排序方式, ...; > select * from zhangwu where money > 1000 order by money asc, id desc; +----+-----------------+-------+ | id | name | money | +----+-----------------+-------+ | 7 | NULL | 5000 | | 6 | damajiangzhichu | 8000 | | 5 | gupiaoshouru | 8000 | | 2 | gongzishouru | 12345 | +----+-----------------+-------+ 4 rows in set (0.00 sec)
-
7)限制查询
- limit:只获取查询结果中从起始偏移量开始的指定行数的记录。
- limit 属于 MySQL 扩展后的语法,在其它数据库上并不能通用。
# 查询单表记录,限制查询 # select 字段名 from 表名 [where 条件] [order by 列名 排序方式] limit [起始偏移量] 获取的行数 > select * from zhangwu where money > 1000 order by money asc, id desc limit 3; +----+-----------------+-------+ | id | name | money | +----+-----------------+-------+ | 7 | NULL | 5000 | | 6 | damajiangzhichu | 8000 | | 5 | gupiaoshouru | 8000 | +----+-----------------+-------+ 3 rows in set (0.01 sec)
-
8)聚合查询
# 查询单表记录,求总数、统计 # select count(字段名) from 表名; > select count(id) from zhangwu; +-----------+ | count(id) | +-----------+ | 7 | +-----------+ 1 row in set (0.00 sec)
# 查询单表记录,求和 # select sum(字段名) from 表名; > select sum(money) from zhangwu; +------------+ | sum(money) | +------------+ | 34917 | +------------+ 1 row in set (0.00 sec)
# 查询单表记录,求平均数 # select avg(字段名) from 表名; > select avg(money) from zhangwu; +-------------------+ | avg(money) | +-------------------+ | 4988.142857142857 | +-------------------+ 1 row in set (0.00 sec)
# 查询单表记录,求最大值 # select max(字段名) from 表名; > select max(money) from zhangwu; +------------+ | max(money) | +------------+ | 12345 | +------------+ 1 row in set (0.01 sec)
# 查询单表记录,求最小值 # select min(字段名) from 表名; > select min(money) from zhangwu; +------------+ | min(money) | +------------+ | 247 | +------------+ 1 row in set (0.00 sec)
-
9)分组查询
- having 是对分组后的结果进行条件过滤,而 where 是在分组前就对记录进行过滤。
- 如果逻辑允许,尽可能的使用 where 先过滤记录,因为这样结果集减小,将对聚合的效率大大提高,最后再根据逻辑看是否用 having 进行再过滤。
# 查询单表记录,分组查询 # select 字段名 from 表名 [where 条件] group by 分组字段名 [order by 排序字段名 排序方式]; > select class, count(no), avg(score) from student group by class; +-------+-----------+------------+ | class | count(no) | avg(score) | +-------+-----------+------------+ | one | 3 | 81.6667 | | two | 2 | 77.5000 | | three | 2 | 83.0000 | +-------+-----------+------------+ 3 rows in set (0.00 sec)
# 查询单表记录,分组后过滤查询 # select 字段名 from 表名 [where 条件] group by 分组字段名 having 分组后的过滤条件 [order by 排序字段名 排序方式]; > select class, count(no), avg(score) from student group by class having avg(score) >= 80; +-------+-----------+------------+ | class | count(no) | avg(score) | +-------+-----------+------------+ | one | 3 | 81.6667 | | three | 2 | 83.0000 | +-------+-----------+------------+ 2 rows in set (0.00 sec)
# 查询单表记录,分组后汇总查询,对分类后的结果进行再汇总 # select 字段名 from 表名 [where 条件] group by 分组字段名 with rollup [order by 排序字段名 排序方式]; > select class, count(no), avg(score) from student group by class with rollup; +-------+-----------+------------+ | class | count(no) | avg(score) | +-------+-----------+------------+ | one | 3 | 81.6667 | | three | 2 | 77.5000 | | two | 2 | 83.0000 | | NULL | 7 | 242.1667 | +-------+-----------+------------+ 4 rows in set (0.00 sec)
-
10)子查询
-
某些情况下,当进行查询的时候,需要的条件是另外一个 select 语句的结果,这个时候,就要用到子查询。
-
用于子查询的关键字主要包括 in、not in、=、!=、exists、not exists、any、all 等。
-
子查询,理论上可以出现在任意位置,在 where 和 from 子句中较多。
-
where 子查询一般返回单行单列、单行多列、多行单列(in、any、all)的数据,from 子查询一般返回多行多列的数据。
-
where 子查询
# 查询单表记录,where 单行单列子查询 # select 字段名 from 表名 where 条件(子查询语句); > select * from student where score > (select score from student where name = "xiao bai" ) order by score asc; +----+-----------+------+-------+-------+----------+ | no | name | age | score | class | address | +----+-----------+------+-------+-------+----------+ | 1 | xiao hei | 18 | 80 | one | NULL | | 6 | li si | 19 | 80 | two | bbbbbbbb | | 3 | zhang san | 18 | 95 | one | NULL | +----+-----------+------+-------+-------+----------+ 3 rows in set (0.00 sec)
# 查询单表记录,where 单行多列子查询 # select 字段名 from 表名 where 条件(子查询语句); > select * from student where (age, class) = (select age, class from student where name = "zhang san" ) order by score asc; +----+-----------+------+-------+-------+---------+ | no | name | age | score | class | address | +----+-----------+------+-------+-------+---------+ | 1 | xiao hei | 18 | 80 | one | NULL | | 3 | zhang san | 18 | 95 | one | NULL | | 4 | wang wu | 18 | 70 | one | NULL | +----+-----------+------+-------+-------+---------+ 3 rows in set (0.00 sec)
- where in 子查询
# 查询单表记录,where 多行单列 in 子查询,与普通的 in 条件类似,如果子查询记录数唯一,还可以使用 = 代替 in # select 字段名 from 表名 where 条件(in 子查询语句); > select * from student where age in (select age from student where class = "one" ) order by age asc; +----+-----------+------+-------+-------+----------+ | no | name | age | score | class | address | +----+-----------+------+-------+-------+----------+ | 4 | wang wu | 18 | 70 | one | NULL | | 1 | xiao hei | 18 | 80 | one | NULL | | 3 | zhang san | 19 | 95 | one | NULL | | 6 | li si | 19 | 80 | two | bbbbbbbb | | 7 | xiao bai | 19 | 79 | three | NULL | | 2 | da bai | 19 | 75 | two | aaaaaaaa | +----+-----------+------+-------+-------+----------+ 6 rows in set (0.00 sec)
- where any 子查询
# 查询单表记录,where 多行单列 =any 子查询,与 in 子查询一样 # select 字段名 from 表名 where 条件(=any 子查询语句); > select * from student where age = any (select age from student where class = "one" ) order by age asc; +----+-----------+------+-------+-------+----------+ | no | name | age | score | class | address | +----+-----------+------+-------+-------+----------+ | 4 | wang wu | 18 | 70 | one | NULL | | 1 | xiao hei | 18 | 80 | one | NULL | | 3 | zhang san | 19 | 95 | one | NULL | | 6 | li si | 19 | 80 | two | bbbbbbbb | | 7 | xiao bai | 19 | 79 | three | NULL | | 2 | da bai | 19 | 75 | two | aaaaaaaa | +----+-----------+------+-------+-------+----------+ 6 rows in set (0.01 sec)
# 查询单表记录,where 多行单列 >any 子查询,大于最小值 # select 字段名 from 表名 where 条件(>any 子查询语句); > select * from student where age > any (select age from student where class = "one" ) order by age asc; +----+-----------+------+-------+-------+----------+ | no | name | age | score | class | address | +----+-----------+------+-------+-------+----------+ | 2 | da bai | 19 | 75 | two | aaaaaaaa | | 3 | zhang san | 19 | 95 | one | NULL | | 6 | li si | 19 | 80 | two | bbbbbbbb | | 7 | xiao bai | 19 | 79 | three | NULL | | 5 | ma liu | 20 | 78 | three | NULL | +----+-----------+------+-------+-------+----------+ 5 rows in set (0.00 sec)
# 查询单表记录,where 多行单列 <any 子查询,小于最大值 # select 字段名 from 表名 where 条件(<any 子查询语句); > select * from student where age < any (select age from student where class = "one" ) order by age asc; +----+----------+------+-------+-------+---------+ | no | name | age | score | class | address | +----+----------+------+-------+-------+---------+ | 1 | xiao hei | 18 | 80 | one | NULL | | 4 | wang wu | 18 | 70 | one | NULL | +----+----------+------+-------+-------+---------+ 2 rows in set (0.00 sec)
- where all 子查询
# 查询单表记录,where 多行单列 >all 子查询,大于最大值 # select 字段名 from 表名 where 条件(>all 子查询语句); > select * from student where age > all (select age from student where class = "one" ) order by age asc; +----+--------+------+-------+-------+---------+ | no | name | age | score | class | address | +----+--------+------+-------+-------+---------+ | 5 | ma liu | 20 | 78 | three | NULL | +----+--------+------+-------+-------+---------+ 1 row in set (0.00 sec)
# 查询单表记录,where 多行单列 <all 子查询,小于最小值 # select 字段名 from 表名 where 条件(<all 子查询语句); > select * from student where age < all (select age from student where class = "one" ) order by age asc; +----+----------+------+-------+-------+---------+ | no | name | age | score | class | address | +----+----------+------+-------+-------+---------+ | 7 | xiao bai | 17 | 79 | three | NULL | +----+----------+------+-------+-------+---------+ 1 row in set (0.00 sec)
- from 子查询
# 查询单表记录,from 多行多列子查询,一般当作一张临时表的方式来处理 # select 字段名 from 表名1 内/外连接表子查询语句; > select B.bno, B.bname, B.bano, C.aname from B, ( select ano, aname, loc from A where ano < 2 ) C where B.bano = C.ano; +-----+----------+------+-----------+ | bno | bname | bano | aname | +-----+----------+------+-----------+ | 0 | zhangsan | 0 | 研发部 | +-----+----------+------+-----------+ 1 row in set (0.00 sec)
-
4.2 查询多表记录
-
当需要同时显示多个表中的字段时,就可以用表连接来实现这样的功能。
-
从大体上分,表连接分为内连接和外连接,它们之间最主要的区别是,内连接仅选出两张表中互相匹配的记录,而外连接会选出其它不匹配的记录。
-
1)多表联合查询
# 查询多表记录,多表联合查询,一定要有表于表之间的关联字段 # select 字段名 from 表名1, 表名2 where 关联条件; > select B.bno, B.bname, B.bano, A.aname from B, A where B.bano = A.ano; +-----+----------+------+-----------+ | bno | bname | bano | aname | +-----+----------+------+-----------+ | 0 | zhangsan | 0 | 研发部 | | 1 | lisi | 2 | 销售部 | +-----+----------+------+-----------+ 2 rows in set (0.00 sec)
-
2)内联查询
# 查询多表记录,内连接查询 # select 字段名 from 表名1 inner join 表名2 on 关联条件; > select B.bno, B.bname, B.bano, A.aname from B inner join A on B.bano = A.ano; +-----+----------+------+-----------+ | bno | bname | bano | aname | +-----+----------+------+-----------+ | 0 | zhangsan | 0 | 研发部 | | 1 | lisi | 2 | 销售部 | +-----+----------+------+-----------+ 2 rows in set (0.00 sec)
-
3)外联查询
# 查询多表记录,左外连接查询,包含所有的左表中的记录甚至是右表中没有和它匹配的记录 # select 字段名 from 表名1 left outer join 表名2 on 关联条件; > select B.bno, B.bname, B.bano, A.aname from B left outer join A on B.bano = A.ano; +-----+----------+------+-----------+ | bno | bname | bano | aname | +-----+----------+------+-----------+ | 0 | zhangsan | 0 | 研发部 | | 1 | lisi | 2 | 销售部 | | 2 | wangwu | NULL | NULL | +-----+----------+------+-----------+ 3 rows in set (0.00 sec)
# 查询多表记录,右外连接查询,包含所有的右表中的记录甚至是左表中没有和它匹配的记录 # select 字段名 from 表名1 left outer join 表名2 on 关联条件; > select B.bno, B.bname, B.bano, A.aname from B right outer join A on B.bano = A.ano order by bno asc; +------+----------+------+-----------+ | bno | bname | bano | aname | +------+----------+------+-----------+ | NULL | NULL | NULL | 财务部 | | 0 | zhangsan | 0 | 研发部 | | 1 | lisi | 2 | 销售部 | +------+----------+------+-----------+ 3 rows in set (0.00 sec)
# 查询多表记录,全外连接查询,包含所有的左表和右表中的记录甚至是没有匹配的记录 # MySQL 是不支持全外的连接的,这里给出的写法适合 Oracle 和 DB2 # select 字段名 from 表名1 left outer join 表名2 on 关联条件; > select B.bno, B.bname, B.bano, A.aname from B full outer join A on B.bano = A.ano order by bno asc;
-
4)记录联合查询
- 我们经常会碰到这样的应用,将两个表的数据按照一定的查询条件查询出来后,将结果合并到一起显示出来。
- 这个时候,就需要用 union 和 union all 关键字来实现这样的功能。
- union all 会把结果直接合并在一起,union 会将合并后的结果进行一次 distinct 去除重复的记录。
# 查询多表记录,记录联合查询 # select 字段名 from 表名1 union | union all select 字段名 from 表名2; > select ano, aname, loc from A union all select bno, bname, bano from B; +-----+-----------+------+ | ano | aname | loc | +-----+-----------+------+ | 0 | 研发部 | aaaa | | 1 | 财务部 | bbbb | | 2 | 销售部 | cccc | | 0 | zhangsan | 0 | | 1 | lisi | 2 | | 2 | wangwu | NULL | +-----+-----------+------+ 6 rows in set (0.00 sec)