以前的SQL基础1中已经介绍了部分Select的内容,可是,实际使用中select 还有不少其余的用法,本文会再介绍部分select的其余用法。mysql
建立2张表用于演示,表名分别为student和class,后续也将继续用这2张表演示,2张表的数据以下:sql
student表测试
class表优化
mysql> select class_no from student; +----------+ | class_no | +----------+ | 201801 | | 201901 | | 201901 | | 201902 | | 201902 | | 201902 | | 201902 | +----------+
可见,查询结果中不少重复的状况。spa
去重使用 DISTINCT 关键字便可code
mysql> select distinct class_no from student; +----------+ | class_no | +----------+ | 201801 | | 201901 | | 201902 | +----------+ 3 rows in set (0.00 sec)
条件查询能够有不少种组合,其中用 AND 或 OR链接不一样的条件,同时能够用in , not in , >、>=、 <、<=、 =等条件进行范围查询等blog
AND的意义至关于“且”,也就是AND先后的条件必须同时成立,例如:排序
查询class_no为201901 而且age>=22的学生索引
mysql> select * from student where age>=22 and class_no='201901'; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | +----+----------+------+----------+ 1 row in set (0.00 sec)
OR意味着“或”,即OR先后条件中的一个知足条件及成立,例如:it
查询student表中age>=24 后者班级号为201801的学生
mysql> select * from student where age>=24 or class_no='201801'; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | | 4 | 乔峰 | 30 | 201801 | | 7 | 杜甫 | 24 | 201902 | +----+----------+------+----------+ 3 rows in set (0.00 sec)
AND和OR的优先级顺序是 AND大于OR,有括号的 先处理括号的 。即 AND和OR同时出现时,先处理AND 再与OR判断,可是出现括号,有出现括号的先处理括号里的。例如:
/** 没有括号 先处理and 最后处理or **/ mysql> select * from student where age<23 and class_no='201902' or class_no='201801'; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 乔峰 | 30 | 201801 | | 3 | 王维 | 21 | 201902 | | 5 | 陈六 | 22 | 201902 | +----+----------+------+----------+ 3 rows in set (0.00 sec) /** 有括号时,先库哦李括号里的or,最后处理 外层的AND ** / mysql> select * from student where age<23 and (class_no='201902' or class_no='201801'); +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 3 | 王维 | 21 | 201902 | | 5 | 陈六 | 22 | 201902 | +----+----------+------+----------+ 2 rows in set (0.00 sec)
建议: 实际使用时,若是嵌套的关系太多,当肯定须要先处理哪一个关系时建议都加上括号,已避免写法错误致使结果与预期不一致。
IN 或 NOT IN的使用频率也是很是高的,例如:
/** in **/ mysql> select * from student where class_no in ('201901','201902'); +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | | 2 | 苏轼 | 20 | 201901 | | 3 | 王维 | 21 | 201902 | | 5 | 陈六 | 22 | 201902 | | 7 | 杜甫 | 24 | 201902 | | 8 | 岳飞 | 23 | 201902 | +----+----------+------+----------+ 6 rows in set (0.00 sec) /** not in **/ mysql> select * from student where class_no not in ('201901','201902'); +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 乔峰 | 30 | 201801 | +----+----------+------+----------+ 1 row in set (0.00 sec)
排序使用order by来进行,能够指定一个或多个字段进行排序,同时能够指定升序(ASC,默认的是升序)或降序(DESC)。
/** 按照age升序排序 **/ mysql> select * from student order by age asc; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 2 | 苏轼 | 20 | 201901 | | 3 | 王维 | 21 | 201902 | | 5 | 陈六 | 22 | 201902 | | 8 | 岳飞 | 23 | 201902 | | 7 | 杜甫 | 24 | 201902 | | 1 | 李白 | 25 | 201901 | | 4 | 乔峰 | 30 | 201801 | +----+----------+------+----------+ 7 rows in set (0.00 sec) /** 按照age降序排列 **/ mysql> select * from student order by age desc; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 乔峰 | 30 | 201801 | | 1 | 李白 | 25 | 201901 | | 7 | 杜甫 | 24 | 201902 | | 8 | 岳飞 | 23 | 201902 | | 5 | 陈六 | 22 | 201902 | | 3 | 王维 | 21 | 201902 | | 2 | 苏轼 | 20 | 201901 | +----+----------+------+----------+ 7 rows in set (0.00 sec) /** 先按照class_no升序,class_no 相同时按照age降序排列 **/ mysql> select * from student order by class_no,age desc; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 乔峰 | 30 | 201801 | | 1 | 李白 | 25 | 201901 | | 2 | 苏轼 | 20 | 201901 | | 7 | 杜甫 | 24 | 201902 | | 8 | 岳飞 | 23 | 201902 | | 5 | 陈六 | 22 | 201902 | | 3 | 王维 | 21 | 201902 | +----+----------+------+----------+ 7 rows in set (0.00 sec)
注:当表的数据量较大时,建议排序字段上有索引。
分页查询在数据展现上是使用频率很是高的功能之一,1其语法为:
select field_names from tbname where filter order by oderby_fieldname limit offset,row_counts
其中 offset是偏移量,即以前遍历了的数据量,row_counts指每页的数据量。
例如,分页遍历其中一个表的记录,每页3条记录,例如:
/** 首页 **/ mysql> select * from student order by id limit 3*0,3; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | | 2 | 苏轼 | 20 | 201901 | | 3 | 王维 | 21 | 201902 | +----+----------+------+----------+ 3 rows in set (0.00 sec) /** 第二页 **/ mysql> select * from student order by id limit 3*1,3; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 乔峰 | 30 | 201801 | | 5 | 陈六 | 22 | 201902 | | 7 | 杜甫 | 24 | 201902 | +----+----------+------+----------+ 3 rows in set (0.00 sec) /** 第三页 **/ mysql> select * from student order by id limit 3*2,3; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 8 | 岳飞 | 23 | 201902 | +----+----------+------+----------+ 1 row in set (0.00 sec)
注: order by 的字段上必定要有索引,不然 可能遍历额结果有重复,相关例子能够自行测试。
不少状况下,咱们都须要进行一些汇总类的操做,即聚合查询。聚合查询一般须要配合GROUP BY关键字进行分组聚合。下面使用几种常见的聚合查询操做。
count是指统计记录条数。
/** 查看student表的记录总数 **/ mysql> select count(*) from student; +----------+ | count(*) | +----------+ | 7 | +----------+ 1 row in set (0.00 sec) /** 查询age大于24的记录数 **/ mysql> select count(*) from student where age>=24; +----------+ | count(*) | +----------+ | 3 | +----------+ 1 row in set (0.00 sec)
/** 按照class_no分组统计,即查询每一个班级的人数 **/
mysql> select class_no, count(*) from student group by class_no; +----------+----------+ | class_no | count(*) | +----------+----------+ | 201801 | 1 | | 201901 | 2 | | 201902 | 4 | +----------+----------+ 3 rows in set (0.00 sec) /**查询每一个班级的人数,同时按照人数降序排列 **/ mysql> select class_no, count(*) from student group by class_no order by count(*) desc ; +----------+----------+ | class_no | count(*) | +----------+----------+ | 201902 | 4 | | 201901 | 2 | | 201801 | 1 | +----------+----------+ 3 rows in set (0.00 sec)
/**查询每一个班级的人数,同时只返回人数大于1个的class_no及人数 **/
mysql> select class_no, count(*) from student group by class_no having count(*)>1 ; +----------+----------+ | class_no | count(*) | +----------+----------+ | 201901 | 2 | | 201902 | 4 | +----------+----------+ 2 rows in set (0.00 sec)
除了count的聚合操做外,还有min(最小)、max(最大) 、avg (平均)、sum(求和)等聚合操做,其操做和count相似。
例如:
mysql> select max(age),min(age),avg(age),sum(age) from student; +----------+----------+----------+----------+ | max(age) | min(age) | avg(age) | sum(age) | +----------+----------+----------+----------+ | 30 | 20 | 23.5714 | 165 | +----------+----------+----------+----------+ 1 row in set (0.00 sec)
当进行查询下的时候 须要查询的条件是另一个select语句的结果的时候能够用到子查询来处理。此时要用in、not in 、exists、not exists以及=、!=等。
例如:
/** 查询存在于class表的student的记录 **/ mysql> select * from student where class_no in (select class_no from class); +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | | 2 | 苏轼 | 20 | 201901 | | 3 | 王维 | 21 | 201902 | | 5 | 陈六 | 22 | 201902 | | 7 | 杜甫 | 24 | 201902 | | 8 | 岳飞 | 23 | 201902 | +----+----------+------+----------+ 6 rows in set (0.00 sec) /** 查询不存在于class表的student的记录 **/ mysql> select * from student where class_no not in (select class_no from class); +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 乔峰 | 30 | 201801 | +----+----------+------+----------+ 1 row in set (0.00 sec)
exists和not exists在此时(子查询不存在null的状况下)查询结果是等价的(查询效率有差别,且和数据量有关),对于此问题,各位能够本身测一下。
当须要同时展现多个表的字段时,须要用表链接的方式将多张表的字段在一个查询中展现。
表链接的方式从大类上来讲能够分为内链接和外链接。
内链接是查询2张表同时存在的记录,即两张表的交集。
例如:
/** 同时查询两张表中class_no 相同的student及class表的全部字段内容 **/ mysql> select * from student a,class b -> where a.class_no=b.class_no; +----+----------+------+----------+----------+--------------+------------------+ | id | stu_name | age | class_no | class_no | class_name | location | +----+----------+------+----------+----------+--------------+------------------+ | 1 | 李白 | 25 | 201901 | 201901 | 2019级01班 | 博学北楼A401 | | 2 | 苏轼 | 20 | 201901 | 201901 | 2019级01班 | 博学北楼A401 | | 3 | 王维 | 21 | 201902 | 201902 | 2019级02班 | 博学北楼B401 | | 5 | 陈六 | 22 | 201902 | 201902 | 2019级02班 | 博学北楼B401 | | 7 | 杜甫 | 24 | 201902 | 201902 | 2019级02班 | 博学北楼B401 | | 8 | 岳飞 | 23 | 201902 | 201902 | 2019级02班 | 博学北楼B401 | +----+----------+------+----------+----------+--------------+------------------+ 6 rows in set (0.00 sec)
注:
a) 例子中是列举出全部字段,全部能够用* ,当须要列出指定字段时,能够列出指定字段名展现,经过表名.字段名的方式列出
b) 内链接的写法能够向上述例子中那样,也能够用inner join ... on...这种方式来写,其中inner能够省略,例如:
mysql> select a.stu_name,b.class_name from student a inner join class b on a.class_no=b.class_no; +----------+--------------+ | stu_name | class_name | +----------+--------------+ | 李白 | 2019级01班 | | 苏轼 | 2019级01班 | | 王维 | 2019级02班 | | 陈六 | 2019级02班 | | 杜甫 | 2019级02班 | | 岳飞 | 2019级02班 | +----------+--------------+ 6 rows in set (0.00 sec)
c) in能够用内链接的方式来改写,尤为是多层子查询时,这也是SQL优化中给的一种方案。例如以前in例子就能够改写为:
mysql> select distinct a.* from student a inner join class b on a.class_no=b.class_no; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | | 2 | 苏轼 | 20 | 201901 | | 3 | 王维 | 21 | 201902 | | 5 | 陈六 | 22 | 201902 | | 7 | 杜甫 | 24 | 201902 | | 8 | 岳飞 | 23 | 201902 | +----+----------+------+----------+ 6 rows in set (0.00 sec)
外链接分为左链接和右链接,其中:
a) 左链接是指包含左边表中的记录,即便左表中含有和右表匹配不上的记录也会保留。
b) 右链接是指包含右边表中的记录,即便右表中含有和左表匹配不上的记录也会保留。
例如:
/** 左链接 **/ mysql> select a.stu_name,b.class_name from student a left join class b on a.class_no=b.class_no; +----------+--------------+ | stu_name | class_name | +----------+--------------+ | 李白 | 2019级01班 | | 苏轼 | 2019级01班 | | 王维 | 2019级02班 | | 陈六 | 2019级02班 | | 杜甫 | 2019级02班 | | 岳飞 | 2019级02班 | | 乔峰 | NULL | /** 改记录的class_no不存在与右表中 **/ +----------+--------------+ 7 rows in set (0.00 sec) /** 右链接 **/ mysql> select a.stu_name,b.class_name from student a right join class b on a.class_no=b.class_no; +----------+--------------+ | stu_name | class_name | +----------+--------------+ | 李白 | 2019级01班 | | 苏轼 | 2019级01班 | | 王维 | 2019级02班 | | 陈六 | 2019级02班 | | 杜甫 | 2019级02班 | | 岳飞 | 2019级02班 | +----------+--------------+
注: 也可使用外链接来改写not in ,例如以前not in的例子能够按照以下方式改写:
mysql> select distinct a.* from student a left join class b on a.class_no=b.class_no where b.class_no is null; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 乔峰 | 30 | 201801 | +----+----------+------+----------+ 1 row in set (0.00 sec)
记录联合是指将多个查询结果合并到一块儿展现,须要用到UNION 、UNION ALL 关键字,其中UNION ALL不对多个查询的结果去重,所有展现出来(即便查询结果彻底相同),union 会对结果中的重复记录进行去重后展现。
例如:
/** union all **/ mysql> select a.stu_name,b.class_name from student a left join class b on a.class_no=b.class_no -> union all -> select a.stu_name,b.class_name from student a right join class b on a.class_no=b.class_no; +----------+--------------+ | stu_name | class_name | +----------+--------------+ | 李白 | 2019级01班 | | 苏轼 | 2019级01班 | | 王维 | 2019级02班 | | 陈六 | 2019级02班 | | 杜甫 | 2019级02班 | | 岳飞 | 2019级02班 | | 乔峰 | NULL | | 李白 | 2019级01班 | | 苏轼 | 2019级01班 | | 王维 | 2019级02班 | | 陈六 | 2019级02班 | | 杜甫 | 2019级02班 | | 岳飞 | 2019级02班 | +----------+--------------+ 13 rows in set (0.00 sec) /** union **/ mysql> select a.stu_name,b.class_name from student a left join class b on a.class_no=b.class_no -> union -> select a.stu_name,b.class_name from student a right join class b on a.class_no=b.class_no; +----------+--------------+ | stu_name | class_name | +----------+--------------+ | 李白 | 2019级01班 | | 苏轼 | 2019级01班 | | 王维 | 2019级02班 | | 陈六 | 2019级02班 | | 杜甫 | 2019级02班 | | 岳飞 | 2019级02班 | | 乔峰 | NULL | +----------+--------------+ 7 rows in set (0.00 sec)