MySQL学习

三、查询(2)(DQL 数据查询语言)

1. 查询结果集的去重

distinct关键字去除重复记录

select distinct JOB from emp;

▲distinct关键字只能出现在所有字段的最前方

select distinct DEPTNO,JOB from emp; // distinct出现在所有字段最前方所表示的是所有字段联合去除重复记录。

案例:统计岗位的数量。select count(distinct JOB) from emp;


2. 连接查询
2.1 什么是连接查询?

在实际开发中,大部分情况下都不是从单表中查询数据,一般都是多张表联合查询,取出最后的结果。在实际开发中,一般一个业务都会对应多张表,比如:学生和班级对应两张表。学生信息和班级信息存储到一张表中,会导致数据存在大量的重复,导致数据冗余。

2.2 连接查询的分类

根据语法出现的年代划分:SQL92、SQL99(比较新的语法)

根据表的连接方式来划分:

内连接:

等值连接:

非等值连接:between…and…

自连接:

外连接:

左外连接:

右外连接:

全连接:(不讲,很少用!)

2.3 连接查询的笛卡尔积现象(笛卡尔乘积现象)。

两张表查询没有条件的限制,最终的查询结果是两张表记录条数的乘积。

案例:找出每个员工(ENAME-emp表)的部门(DNAME-dept表)名称,要求显示员工名和部门名(ENAME-DEPTON-DNAME,DEPTON是两张表共有的)。DEPTON是部门 编号。

select e.ENAME,e.DEPTNO,d.DNAME from emp e,dept d; // 给emp和dept表起别名ename和dename要联合起来一起显示

关于表的别名的好处:①执行效率高②可读性好

2.4 如何避免笛卡尔积现象

加条件进行过滤。

避免了笛卡尔积现象,不会减少记录的匹配次数,只不过显示的是有效记录。

找出每个员工的部门名称,要求显示员工名和部门名:select

e.ename,e.deptno,d.dname 

		from 

				emp e,dept d 

		where 
				// SQL92,以后不用
				e.deptno = d.deptno;
2.5 内连接之等值连接

最大的特点:条件是等量关系。

案例:找出每个员工的部门名称,要求显示员工名和部门名(SQL92太老了,不用了)

SQL99(常用的):

select 

		e.ename,d.dname 

from 

		emp e 

inner join

		dept d 

on

		e.emp = d.dept;

SQL99语法结构更清晰,表的连接条件和后来的where条件分离。

2.6 内连接之非等值连接

最大的特点:连接条件中的关系是非等量关系。

案例:找出每个员工的工资等级,要求显示员工名、工资、工资等级(工资在最低区间到最高区间之内为一个等级)。

select 

		e.ename,s.grade,e.sal  

from 

		emp e 

join 

		salgrade s 

on 

		e.sal between s.losal and s.hisal;
2.7 内连接之自连接

最大特点:一张表看作两张表,自己连接自己。(相当于把一张表复制一份变成两张表用)自连接等值非等值均可。

案例:找出每个员工的上级领导,要求显示员工名和对应的领导名。

select 

		a.ename as '员工',b.ename as '领导'

from 

		emp a 

join 

		emp b 

on 

		a.mgr = b.empno;
2.8 外连接

2.8.1 定义

内连接:假设A和B表连接,使用内连接的话,凡是A表和B表能够匹配上的记录查询出来,这就是内连接,AB两张表没有主副之分,两张表是平等的。

外连接:假设A和B表连接,使用外连接的话,AB两张表中,有一张表是主表,一张表是副表,主要查询主表中的数据,捎带着查询副表中的数据。当副表中的数据没有和主表中的数据匹配上,副表自动模拟出NULL与之匹配。——> 主表的数据是无论如何都要查出来的

2.8.2 外连接(outer)的分类

左外连接(左连接):表示左边的表是主表。left join表示坐标的表是主表。

右外连接(右连接):表示右边的表是主表

左连接有右连接的写法,右连接有左连接的写法。

案例:找出每个员工的上级领导。左外连接:


select 

		a.ename as '员工',b.ename as '领导' 

from 

		emp a

left outer join 

		emp b 

on 

		a.mgr = b.empno;

KING在内连接查询时是没有数据的。

右外连接写法:

select 

		a.ename as '员工' ,b.ename as '领导' 

from 

		emp b 

right outer join 

		emp a

on 

		a.mgr = b.empno;

▲外连接最主要的特点:主表的数据无条件的全部查询出来。

案例:找出哪个部门没有员工。

用外连接(dept表是主表):

select 

		d.*

from 

		dept d 

left join 

		emp e 

on 

		e.deptno = d.deptno

where

		e.empno is null;
2.9 三张表的连接查询

案例:找出每个员工的部门名称以及工资等级。

注意:… A join B join C on …表示A表和B表先进行表连接,连接之后和C表继续进行表连接。(一个join加一个on,连接一次给一次连接条件)

select 

		e.ename,e.deptno,s.grade

from

		emp e

join 

		dept d

on

		e.deptno = d.deptno

join

		algrade s

on

		e.sal between s.losal and s.hisal;

案例:找出每个员工的部门名称以及工资等级以及上级领导。(KING必须呗=被查出来,所以只能用外连接)

select 

		e.ename,d.deptno,e1.ename

from

		emp e

left join 

		dept d

on

		e.deptno = d.deptno

left join

		emp e1

on

		e.mgr = a.empno;

🔺注意分清什么时候用内连接查询,什么时候用外连接查询!


3.1 定义

子查询就是select语句中嵌套select语句,被嵌套的select语句是子查询。

子查询可以出现的位置:

select

		..(select)..

from

		..(select)..

where

		..(select)..
3.2 where子句中使用子查询

案例:找出高于平均薪资的员工信息。

select * from emp where sal > (select avg(sal) from emp);
3.3 from后面嵌套子查询

用括号括起来一个语句形成的新表,可以当作一个新的表使用。

from后面只能跟表,但这个表可以是一条SQL语句。

3.3.1 案例:找出每个部门平均薪水的等级。

每个部门的平均薪水(按照部门编号分组):select deptno,avg(sal) as avgsal from emp group by deptno;(起别名)

把第一步得出的表当作临时表t,和薪资表连接使用,条件是t.avgsal between s.losal and s.hisal

select t.*,s.grade from (select deptno,avg(sal) as avgsal from emp group by deptno) t join salgrade s on t.avgsal between s.losal and s.hisal;

3.3.2 案例:找出每个部门平均的薪水等级。

第一步:找出每个人薪水的等级。select e.ename,e.deptno,e.sal,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal;

第二步:分部门。第一步得到的作为新表,按照部门编号的字段分组求等级的平均值。select t.deptno,avg(t.grade) as avggrade from (select e.ename,e.deptno,e.sal,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal) t group by deptno; // ❌冗余做法,数据都有,不用当作临时表

select 

		e.deptno,avg(s.grade )

from

		emp e 

join 

		salgrade s 

on 

		e.sal between s.losal and s.hisal

group by

		e.deptno;
3.4 在select后面嵌套子查询

案例:找出每个员工所在的部门名称,要求显示员工名和部门名。

之前的写法:select e.ename,e.deptno,d.dname from emp e join dept d on e.deptno = d.deptno;

子查询的写法:select e.ename,(select d.dname from dept d where e.deptno = d.deptno) as dname from emp e;


4. union(可以将查询结果集相加)

案例:找出工作岗位是SALESMAN和MANAGER的员工。

第一种写法:select ename,job from emp where job = ‘salesman’ or job = ‘manager’;

第二种写法:select ename,job from emp where job in (‘salesman’,‘manager’);

第三种写法(使用union):

select 

		ename,job 
		
from 

		emp 
where 
		job = 'salesman' 

union

select 
		
		ename,job 
		
from 
		emp 
		
where 

		job = 'manager' ;

select ename,job from emp where job = ‘salesman’ union select ename,job from emp where job = ‘manager’ ;(与前两种写法不同的是,job的结果是按照两种联合顺序的,一样的job是挨着的)

union可以将两张不相干的表中的数据拼接在一起显示。两次查询结构的列数需要一样。


5. limit(★重点★分页查询必备)
5.1 特点

limit是MySQL中特有的,其他数据库中都没有,不通用。(Oracle中有一个相同的机制,叫做rownum)

5.2 作用

limit取结果集中的部分数据。

5.3 语法机制

limit startIndex,length

startIndex表示起始位置,从0开始,0表示第一条数据。(不写起始位置默认是0)

length表示取几个。

案例:取数工资前5名的员工。select ename,sal from emp order by sal desc limit 0,5;

limit是SQL语句中最后执行的环节。

select			5

		....

from			1

		...

where			2

		...

group by		3

		...

having			4

		...

order by		6

		...

limit				7

		...;
5.4 通用的标准分页SQL

每页显示3条记录:第一页0,3;第二页3,3;第三页:6,3;…

每页显示pagesize条记录,第pageNo页:(pageNo-1)*pagesize,pagesize