1、取得每个部门最高薪水的人员名称(要求显示部门编号、人员名称和薪资)
第一步:查询每个部门的最高薪资
SELECT
deptno,max(sal) as maxsal
FROM
emp
GROUP BY
deptno;
第二步:把上面查询结果当做临时表t,和emp e表做连接查询,条件:t.deptno = e.deptno and t.maxsal = e.sal
SELECT
e.deptno,e.ename,e.sal
FROM
(SELECT deptno,max(sal) as maxsal FROM emp GROUP BY deptno) t
JOIN
emp e
ON
t.deptno = e.deptno and t.maxsal = e.sal;
2、哪些人的薪水在部门的平均薪水之上,要求显示员工姓名、员工薪水和部门编号和部门平均薪水
第一步:查询部门平均薪水
SELECT deptno,avg(sal) as avgsal FROM emp GROUP BY deptno;
第二步:将上表作为临时表t ,与emp as e表做连接查询, 条件:t.deptno = e.deptno and e.sal > t.avgsal
SELECT
e.deptno,e.ename,e.sal,t.avgsal
FROM
(SELECT deptno,avg(sal) as avgsal FROM emp GROUP BY deptno) t
JOIN
emp e
ON
t.deptno = e.deptno and e.sal > t.avgsal;
3、取得部门中(所有人的)平均的薪水等级(显示部门编号和薪水等级的平均数)
分析:本题是"平均的薪水等级"。应该是先查询薪水等级,再计算等级的平均值。
如果是计算"平均薪水的等级"。应该是先计算平均薪水,然后查看平均薪水的等级
第一步:查询(所有人)的薪水等级
SELECT
e.deptno,s.grade
FROM
emp e
JOIN
salgrade s
ON
e.sal between losal and hisal;
分析:对上面的查询直接进行分组, 求grade的平均值
SELECT
e.deptno,avg(grade)
FROM
emp e
JOIN
salgrade s
ON
e.sal between losal and hisal
GROUP BY
e.deptno;
4、不准用分组函数(Max() ),取得最高薪水(要求显示 员工名称和薪水)
分析:因为不能使用分组函数,要想取得最高薪水,需要对薪水进行降序排列,然后使用limit来取得记录。
方案一:
SELECT
ename,sal
FROM
emp
ORDER BY
sal desc
LIMIT
1;
方案二:通过自连接查询出所有小于最高工资的工资。然后查询不在这些工资之内的工资就是最高工资
第一步:查询出所有小于最高工资的工资
SELECT
distinct e.sal
FROM
emp e
JOIN
emp ee
ON
e.sal < ee.sal; #查询出所有小于ee表的工资,只有e表中的工资5000不小于ee表中的任何一个工资,所以5000不包括在内。
第二步:查询出最高工资
SELECT
ename,sal
FROM
emp
WHERE
sal not in (SELECT distinct e.sal FROM emp e JOIN emp ee ON e.sal < ee.sal);
说明:方案二虽然复杂了一些,但却是一种不一样的思路,需要我们好好理解一下,也许今后会用到哦!
5、取得平均薪水最高的部门的部门编号
第一种方案:按部门编号分组,计算平均薪水,然后按降序排列,取第一行数据。
SELECT
deptno,avg(sal) as avgsal
FROM
emp
GROUP BY
deptno
ORDER BY
avgsal desc
LIMIT
1;
第二种方案:统计出每个部门的平均薪水,然后再查询最大值。
第一步:统计每个部门的平均薪水
SELECT
deptno,avg(sal)
FROM
emp
GROUP BY
deptno;
第二步:把上一步的查询结果当做一张临时表t,统计最大值
SELECT
t.deptno,max(avgsal)
FROM
(SELECT deptno,avg(sal) as avgsal FROM emp GROUP BY deptno) t;
6、取得平均薪水最高的部门的部门名称
分析:因为薪水和部门名称分别在emp表和dept表中,为此需要进行连接查询
第一种方案:
SELECT
d.dname,max(avgsal)
FROM
(SELECT deptno,avg(sal) as avgsal FROM emp GROUP BY deptno) t #FROM中的子查询获取的是每个部门的平均薪资
JOIN
dept d
ON
d.deptno = t.deptno;
第二种方案:通过连接查询获取部门名称,然后通过GROUP BY分组查询取得部门平均薪资,随后利用ORDER BY进行排序(降序desc)最后通过分页显示截取第一名就是最后结果。
SELECT
d.dname,avg(sal) as avgsal
FROM
emp e
JOIN
dept d
ON
e.deptno = d.deptno
GROUP BY
d.dname
ORDER BY
avgsal desc
LIMIT
1;
7、求平均薪水的等级最低的部门的部门名称
分析:首先按部门进行分组,查询部门最低的平均薪水,然后连接查询找到部门名称
SELECT
deptno,avg(sal) avgsal
FROM
emp
GROUP BY
deptno
ORDER BY
avgsal asc
LIMIT
1;
把上面的查询结果作为临时表t,与表salgrade进行连接查询,查询工资等级,条件:t.avgsal between s.losal and s.hisal
还需要与表dept d进行连接查询,查询部门名称,条件:t.deptno = d.deptno
SELECT
d.deptno,d.dname,t.avgsal,s.grade
FROM
(SELECT deptno,avg(sal) avgsal FROM emp GROUP BY deptno ORDER BY avgsal asc LIMIT 1) t
JOIN
salgrade s #通过与表salgrade进行连接查询获取薪资等级
ON
t.avgsal between s.losal and s.hisal
JOIN
dept d #通过与表dept进行连接查询获取部门名称
ON
t.deptno = d.deptno;
8、取得比普通员工(员工代码没有在 mgr 字段上出现的) 的最高薪水还要高的领导人姓名
分析:首先在mgr字段中利用distinct去重查询出所有领导的员工编号。(只要员工编号不在领导编号里的都是普通员工)
第一步:查询领导编号
SELECT
distinct mgr
FROM
emp
WHERE
mgr is not null;
第二步:员工编号不在领导编号里的就是普通员工,查询这些人的最高工资
SELECT
max(sal)
FROM
emp
WHERE
empno not in (SELECT distinct mgr from emp where mgr is not null);
第三步:查询sal比上面查询结果(最高工资)高的员工信息(比“普通员工的最高薪水”已经把普通员工排除在外了,所以一定是领导!为此这里不需要判断是不是领导了)
SELECT
ename,sal
FROM
emp
WHERE
sal > (SELECT max(sal) FROM emp WHERE empno not in (SELECT distinct mgr from emp where mgr is not null));
9、取得薪水最高的前五名员工
分析:按sal字段降序排序,取前五名即可
SELECT
empno,ename,sal
FROM
emp
ORDER BY
sal desc
LIMIT
5;
10、取得薪水最高的第六到第十名员工
分析:按sal字段降序排序,取第6到第10名即可
SELECT
empno,ename,sal
FROM
emp
ORDER BY
sal desc
LIMIT
5,5;
11、取得最后入职的 5 名员工
分析:按入职日期按降序排序,取前五名即可
SELECT
empno,ename,hiredate
FROM
emp
ORDER BY
hiredate desc #这里对日期的比较是1981-01-20大于1981-01-19,所以降序排列的时候晚入职的会排在早入职的前面
LIMIT
5;
12、取得每个薪水等级有多少员工
分析:首先查询出每个员工的薪水等级,然后根据薪水等级进行分组统计数量即可
SELECT
s.grade as grade,count(*)
FROM
emp e
JOIN
salgrade s
ON
e.sal between s.losal and s.hisal
GROUP BY
grade;
13、详见上一篇"SQL面试题"
14、列出所有员工及领导的姓名
分析:因为员工和领导都在一张表中,所以需要使用自连接,又因为需要查询所有员工所以需要使用外连接员工表作为主表(员工表中有一位员工没有领导,不使用外连接显示不出来)
第一种方案:左连接
SELECT
e.ename as '员工名',ee.ename as '领导名'
FROM
emp e
LEFT JOIN
emp ee
ON
e.mgr = ee.empno; #此处需要注意:员工表的领导编号=领导表的员工编号
第二种方案:右连接
SELECT
e.ename '员工名',ee.ename '领导名'
FROM
emp ee
RIGHT JOIN
emp e
ON
e.mgr = ee.empno;
15、列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称
分析:首先找出每个员工的直接上级领导,这张表作为临时表,让它与emp表进行连接,条件:
SELECT
e.empno '员工编号',e.ename as '员工名',e.hiredate as '员工受雇日期',ee.ename as '领导名',ee.hiredate as '领导受雇日期',d.dname '部门名称'
FROM
emp e
LEFT JOIN #通过左外链接能查询出所有员工的直接上级领导
emp ee
ON
e.mgr = ee.empno
JOIN #通过连接查询查询出部门名称
dept d
ON
e.deptno = d.deptno
WHERE
e.hiredate < ee.hiredate; #通过条件筛选出员工入职日期早于领导入职日期的信息
16、列出部门名称和这些部门的员工信息, 同时列出那些没有员工的部门
分析:员工信息和部门名称在两张表上,并且有一个部门没有员工,要想显示出所有部门就需要让部门表做主表使用外连接
SELECT
e.*,d.dname
FROM
dept d
LEFT JOIN
emp e
ON
d.deptno = e.deptno;
17、列出至少有 5 个员工的所有部门
分析:需要按部门进行分组查询,然后选出count(*) >= 5 的部门
SELECT
deptno,count(*)
FROM
emp
GROUP BY
deptno
HAVING
count(*) >= 5;
18、列出薪金比"SMITH" 多的所有员工信息
分析:首先查出'SMITH'的薪资,然后查询比'SMITH'薪资高的员工
SELECT
ename,sal
FROM
emp
WHERE
sal > (SELECT sal FROM emp WHERE ename = 'SMITH');
19、列出所有"CLERK"( 办事员) 的姓名及其部门名称, 部门的人数
分析:查询信息不在一张表中,需要使用连接查询;查询部门人数需要按部门进行分组
第一步:通过连接查询,查出工作岗位是'CLERK'的员工姓名、部门名称、部门编号和工作岗位
SELECT
e.deptno,e.ename,e.job,d.dname
FROM
emp e
JOIN
dept d
ON
e.deptno = d.deptno
WHERE
job = 'clerk';
第二步:通过分组查询统计出每个部门的人数
SELECT
deptno,count(*)
FROM
emp
GROUP BY
deptno;
第三步:将前面两步的查询结果作为临时表,查询出最后结果
SELECT
a.ename,a.job,a.dname,b.count
FROM
(SELECT e.deptno,e.ename,e.job,d.dname FROM emp e JOIN dept d ON e.deptno = d.deptno WHERE job = 'CLERK') a
JOIN
(SELECT deptno,count(*) as count FROM emp GROUP BY deptno) b
ON
a.deptno = b.deptno;
20、列出最低薪金大于 1500 的各种工作及从事此工作的全部雇员人数
分析:题中查询各种工作,因此需要根据job来分组查询,分组后还需要筛选出min(sal) > 1500 的组别,然后统计每组人数。
SELECT
Job,count(*)
FROM
emp
GROUP BY
job
HAVING
Min(sal) > 1500;
21、列出在部门"SALES"< 销售部> 工作的员工的姓名, 假定不知道销售部的部门编号
第一步:查询销售部的部门编号
SELECT
deptno
FROM
dept
WHERE
dname = 'SALES';
第二步:将上表查询结果作为条件查询员工姓名
SELECT
ENAME
FROM
EMP
WHERE
DEPTNO = (SELECT DEPTNO FROM DEPT WHERE DNAME = 'SALES');
22、列出薪金高于公司平均薪金的所有员工, 所在部门, 上级领导, 雇员的工资等级。
第一步:查询公司平均薪资
SELECT
avg(sal)
FROM
emp;
第二步:分析查询所在部门需要与dept表连接查询,查询上级领导并显示所有员工需要外自连接查询,查询工资等级需要与salgrade表连接查询。
SELECT
e.ename, d.dname,ee.ename as '上级领导',s.grade
FROM
emp e
JOIN
dept d
ON
e.deptno = d.deptno
LEFT JOIN
emp ee
ON
e.mgr = ee.empno
JOIN
salgrade s
ON
e.sal between losal and hisal
WHERE
e.sal > (SELECT avg(sal) FROM emp);
23、 列出与"SCOTT" 从事相同工作的所有员工及部门名称(查询结果不包括'SCOTT')
第一步:查询出'SCOTT'从事的工作
SELECT
job
FROM
emp
WHERE
ename = 'SCOTT';
第二步:需要查询部门名称就要通过与dept表进行连接查询,并将第一步的查询结果作为条件进行查询
SELECT
e.ename,d.dname,e.job
FROM
emp e
JOIN
dept d
ON
e.deptno = d.deptno
WHERE
job = (SELECT job FROM emp WHERE ename = 'SCOTT') and ename != 'SCOTT' ;
24、列出薪金等于部门30中任意一位员工的薪金的其他部门员工的姓名和薪金。
第一步:查询出部门30的所有员工的薪资
SELECT
sal
FROM
emp
WHERE
deptno = 30;
第二步:查询其他部门的员工薪资等于上表中任意一个薪资的一个姓名和薪资
SELECT
ename,sal
FROM
emp
WHERE
sal in(SELECT sal FROM emp WHERE deptno = 30) and deptno <> 30;
25、列出薪金高于在部门 30 工作的所有员工的薪金的员工姓名和薪金. 部门名称
第一步:查询出部门30的最高工资
SELECT
max(sal)
FROM
emp
WHERE
deptno = 30;
第二步:查询工资高于上面查询结果的员工姓名、薪资和部门名称,因为部门名称在另一张表中,所以需要连接查询
SELECT
e.ename,e.sal,d.dname
FROM
emp e
JOIN
dept d
ON
e.deptno = d.deptno
WHERE
e. sal > (SELECT max(sal) FROM emp WHERE deptno = 30);
26、列出在每个部门工作的员工数量, 平均工资和平均服务期限。
在这里我们首先介绍一个计算两个日期差的函数TimeStampDiff()
语法:
TimeStampDiff(间隔类型,前一个日期,后一个日期)
举例:计算两个日期的年差
timestampdiff(YEAR, hiredate, now())
此函数的参数'间隔类型'可以是下面内容:
SECOND 秒,
MINUTE 分钟,
HOUR 小时,
DAY 天,
WEEK 星期
MONTH 月,
QUARTER 季度,
YEAR 年
分析:题中出现每个部门所以需要按部门分组;计算员工数量使用count(ename),计算平均工资使用avg(sal),计算平均服务时长使用avg(timestampdiff()),还有需要注意的地方:本题40部门没有员工,统计员工数量不使用count(*),计算平均工资和平均服务时长时需要处理null,所以需要使用ifnull()函数。
SELECT
d.deptno,count(e.ename),avg(ifnull(sal,0)),ifnull(avg(timeStampDiff(year,hiredate,now())),0)
FROM
emp e
RIGHT JOIN
dept d #这里使用右连接的目的就是为了显示出所有的部门(包括没有员工的40部门)
ON
e.deptno = d.deptno
GROUP BY
d.deptno; #这里的分组字段也可以把d.dname和d.loc都写上,这样在SELECT后面就可以多写这两个字段,最终显示更详细
27、 列出所有员工的姓名、部门名称和工资。
SELECT
e.ename,d.dname,e.sal
FROM
emp e
JOIN
dept d
ON
e.deptno = d.deptno;
28、列出所有部门的详细信息和人数
SELECT
d.*,count(e.ename)
FROM
emp e
RIGHT JOIN
dept d
ON
e.deptno = d.deptno
GROUP BY
e.deptno;
29、列出各种工作的最低工资及从事此工作的雇员姓名
第一步:按工作进行分组找出最低工资
SELECT
job,min(sal) as minsal
FROM
emp
GROUP BY
job;
第二步:将上表作为临时表t,与表emp e通过连接查询得到结果,连接条件:e.job = t.job and t.minsal = e.sal
SELECT
e.ename,e.job,e.sal
FROM
emp e
JOIN
(SELECT job,min(sal) as minsal FROM emp GROUP BY job) t
ON
e.job = t.job and t.minsal = e.sal;
30、列出各个部门的 MANAGER( 领导) 的最低薪金
分析:按条件job = 'MANAGER'选出所有的'MANAGER',然后对'MANAGER'按deptno进行分组找到最低薪资
SELECT
DEPTNO,JOB,MIN(SAL) #这里为什么可以写JOB,是因为查询出的所有人的工作岗位都是一样的,为此可以写JOB。
FROM
EMP
WHERE
JOB = 'MANAGER'
GROUP BY
DEPTNO;
31、列出所有员工的年工资, 按年薪从低到高排序
SELECT
ename,((sal + ifnull(comm,0) ) * 12) as '年薪'
FROM
emp
ORDER BY
年薪 asc; #注意ORDER BY 后面跟的是字段名,不能写成'年薪'
32、求出员工领导的薪水超过3000的员工名称与领导
SELECT
e.ename '员工名',ee.ename '领导名',ee.sal as '领导薪资'
FROM
emp e
JOIN
emp ee
ON
e.mgr = ee.empno
WHERE
ee.sal > 3000;
33、求出部门名称中, 带'S'字符的部门员工的工资合计、部门人数
第一步:查询出部门名称中带'S'的部门
SELECT
deptno,dname
FROM
dept
WHERE
dname like '%S%';
第二步:在上面查询出的部门中统计工资合计、部门人数
SELECT
t.dname,ifnull(sum(e.sal),0),count(e.ename)
FROM
emp e
RIGHT JOIN
(SELECT deptno,dname FROM dept WHERE dname like '%S%') t
ON
e.deptno = t.deptno
GROUP BY
t.deptno,t.dname;
34、给任职日期超过 40 年的员工加薪 10%.
分析:本题需要计算任职期限需要使用timestampdiff()函数
我们首先查看一下调整前每个人的工资情况和服务期限
SELECT ename,sal,timestampdiff(year,hiredate,now()) from emp;
为了看出满足条件的加薪,不满足条件的没加薪,所以将本题改为:任职期限超过40年的员工
对满足条件的员工工资进行调整
Update emp set sal = sal *1.1 where timestampdiff(year,hiredate,now()) > 40;
查看调整后每个人的工资情况和服务期限
Select ename,sal,timestampdiff(year,hiredate,now()) from emp;