34道MySql练习题
34道MySql练习题
前言
在web中最基础的部分就是写sql语句,大部分都是增删改查。但是水平实在是一言难尽,故此重新复习一遍。
难度星级之攻略
都是自己亲身体验过的,随便打几颗星星玩(可能不太准确,笑)。有些知识点不熟悉所有显得有点难。还有一些题目不算难但是过程很绕或者是表述很绕,为了出题而出题,题目看懂了就还好。
PS:第13题是面试题,有单独的SQL文件。与其余的33道题的sql没有关联。
难度系数 | 题目序号 |
---|---|
★☆☆☆(有手就行) | 18、21、23、27、30 |
★★☆☆(基础部分) | 1、2、9、10、11、17、23、25、29 |
★★★☆(还可以吧) | 3、4、5、6、8、12、14、15、16、25、 |
★★★★(阅读理解) | 7、13、19、20、22、24、26、28、33 |
SQL文件及描述
|
|
1、取得每个部门最高薪水的人员名称
思路:
- 取得每个部门最高薪水(按部门编号分组,找出每一组最大值)
|
|
- 将以上的表作为一张临时表
t
,t
和emp
表连接,条件是t.deptno=e.deptno and t.maxsal=e.sal
完整SQL:
|
|
2、哪些人的薪水在平均薪水之上
思路:
- 求出每个部门的平均薪水
|
|
- 将上面的查询结果当做
t
表,t
和emp
表连接,条件部门编号相同,t.avgsal < e.SAL
完整SQL:
|
|
3、取得部门中(所有人的)平均的薪水等级
区别:
- 平均的薪水等级:先计算每个薪水的等级,然后找出薪水等级的平均值。
- 平均薪水的等级:先计算平均薪水,再找出每个平均薪水的等级。
思路:
-
根据部门找出每个人的薪水等级
epm e
和salgrade s
表连接连接条件:
e.sal between s.losal and s.hisal
我们可以在后面加上
order by e.deptno
排序一下
|
|
我们需要求的平均的薪水等级,就把每个相同部门的人的等级相加,然后就平均值即可。
2. 基于上面的表按照deptno分组,
|
|
我们会发现,上面的那个表并不需要成为一张临时表,我们仅仅通过deptno
把上面的表做一次分组就好了。但是分组之后出现了一个问题,如果在select
语句中仍然存在e.ename
,那么会报错,这是什么原因呢。使用group by
分组聚合,那么就把原先的相同的部门聚合成了一组,这个时候,他们相同的字段只有部门编号,而名字在聚合中是不同的,我们提取不了不同的值。
4、不准用组函数(Max),取得最高薪水(给出两种解决方案)
- 第一种:使用
order by sal
,通过sal
进行排序,desc
降序,再使用limit
分页,取第一条数据即可。【升序(ASC
)或降序(DESC
)】
|
|
- 第二种:(不讲规矩)直接使用max,最简单的方法。
|
|
- 第三种:表的自连接+去重+not in
- 把同一个emp表做两份,进行自连接,判断条件a表的sal与b表的sal的大小比较。
- 去重,通过比较,留不下的是5000,因为5000最大,条件不成立。
- 把上面的表当做一个临时表,使用where进行条件判断,查出不在临时表中数据。
|
|
5、取得平均薪水最高的部门的部门编号(至少给出两种解决方案)
- 第一种:使用排序,limit1
第一步: 找出每个部门的平均薪水
|
|
第二步:根据平均薪水进行降序排序,取第一个数值
|
|
- 第二种:使用max
第一步同上,
|
|
第二步使用max,不能直接在上面套一个max
,max(avg(e.sal))
写法是错误的,
|
|
拿到最大值:
|
|
第三步使用having与第一步的表进行连接
|
|
附上自己错误的用法:
Tips: Having的用法:
having字句可以让我们筛选成组后的各种数据,where字句在聚合前先筛选记录,也就是说作用在group by和having字句前。而 having子句在聚合后对组记录进行筛选。
HAVING 只能与 SELECT 语句一起使用。 HAVING 通常在 GROUP BY 子句中使用。 如果不使用 GROUP BY 子句,则 HAVING 的行为与 WHERE 子句一样。
- 使用max的第二种思路,与
dept
表连接(这是视频里一个同学的写法,但是看弹幕里mysql8.0以后好像会报错)
|
|
6、取得平均薪水最高的部门的部门名称
- 按
deptno
分组,排序,limit1
只选最大值。再与dept
表按t.deptno = d.deptno
连接
|
|
这里的第二种写法通过d表的dname进行分组聚合,那么在select中就可以直接使用d.dname字段了。算是一种讨巧的方法。
7、求平均薪水的等级最低的部门的部门名称
我的思路:先求部门的平均薪水等级,(正好前面第三题与这个类似)再连表升序选第一个搞定。
|
|
我们上面的思路实际上是求平均的薪水等级按照grade求平均数。
而题目让求的是平均薪水的等级使用sal求平均数。
但是这样看似得到了答案,但是却不严谨。我们来思考两个问题。
平均薪水最低,那么薪水等级一定是最低。
平均薪水不是最低,但也有可能是等级最低。
打个比方,薪资在1000-1500,的属于薪资等级1,1500-2000的属于薪资等级2。那么有三个员工,工资分别是1100,1300,1800。毫无疑问,工资最低的1100,薪水等级也是最低的1。而工资不是最低的1300,薪资等级却也是1。
因此上面的sql语句是错误的,而且不够严谨。正确思路如下,
思路: 第一步:找出每个部门的平均薪水(按照部门分组求平均值)
|
|
第二步:找出每个部门的平均薪水等级。以上t表和salgrade表连接,条件是t.avgsal between s.losal and s.hisal
,查出此表之后,我们还缺一个该如何查出最低的等级。
|
|
我们可以想到,求最低等级 ==> 平均薪水最低的等级一定是最低的,因此我们做的是通过最低的平均薪水来查出最低的薪水等级。这样做很严谨,因为等级是一个区间,就算有两个相同的最低等级也能查的出来,而不是使用limit1只能查出来一个。
- 步骤一:查到最低的平均薪水。
|
|
- 步骤二: 将上表加入salgrade,通过最低的平均薪水查到最低的薪水等级。 条件是 avgsal between losal and hisal
|
|
我们把数值替换成sql语句
|
|
- 步骤三:将上面大致思路的第二步中再加入一个where条件即加入上面这张表
|
|
至此,我们基本已经完成了。但是想要查询的字段不是部门编号,而是名称。只需要在这行中连接一下dept表。from (select deptno,avg(sal) as avgsal from emp group by deptno ) t
|
|
8、取得比普通员工(员工代码没有在mgr字段上出现的)的最高薪水还要高的领导人姓名
|
|
员工编号没有在以上范围内的都是普通员工。
思路:
步骤一: 找出普通员工的最高薪水。
|
|
|
|
会发现查出来的是NULL。Tips: not in在使用的时候,后面的小括号记得排除NULL。
|
|
步骤二:找出高于1600的
|
|
9、取得薪水最高的前五名员工
|
|
10、取得薪水最高的第六到第十名员工
|
|
11、取得最后入职的5名员工
日期降序排列。。。。从最近的日期到最远的日期。
|
|
12、取得每个薪水等级有多少员工
第一步:找出每个员工的薪水等级
|
|
第二步:继续分组统计数量
|
|
小Tips: 如果存在分组函数,比如这里
group by s.grade
那么在select 中只能写分组的字段和分组函数。
13、面试题
SQL 文件
|
|
描述
有3个表S(学生表),C(课程表),SC(学生选课表)
S(SNO,SNAME)代表(学号,姓名)
C(CNO,CNAME,CTEACHER)代表(课号,课名,教师)
SC(SNO,CNO,SCGRADE)代表(学号,课号,成绩)
问题1:找出没选过“黎明”老师的所有学生姓名。
|
|
问题2:列出2门以上(含2门)不及格学生姓名及平均成绩。
|
|
问题3:即学过1号课程又学过2号课所有学生的姓名。
|
|
14、列出所有员工及其领导的姓名
|
|
小Tips:
left join(左联接):返回左表中的所有记录以及和右表中的联接字段相等的记录。
right join(右联接):返回右表中的所有记录以及和左表中的联接字段相等的记录。
inner join(等值联接,join):只返回两个表中联接字段相等的记录。
相关文章:https://segmentfault.com/a/1190000017369618
15、列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称
思路:
emp a
员工表emp b
领导表- 受雇日期早于领导 ==>
a.mgr = b.empno and a.hiredate<b.hiredate
|
|
小Tips:多表连接,多次使用join连接
16、列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门
|
|
小Tips:使用右外连接,
right join
17、列出至少有5个员工的所有部门
|
|
18、列出薪金比"SMITH"多的所有员工信息
|
|
19、列出所有"CLERK"(办事员)的姓名及其部门名称,部门的人数
|
|
到这一步很容易,那么后面的问题来了,怎么把部门的人数连上?
如果直接在使用group by d.dname分组,那么select中就无法使用e.name字段,还是查不出来。因此还是老老实实想办法用临时表吧。
在上表中再加一个字段,d.deptno。这样在对emp表通过deptno做分组得出数量的同时有了deptno字段。既然有了相同的字段,那么就可以愉快的使用连表进行join了。
|
|
20、列出最低薪金大于1500的各种工作及从事此工作的全部雇员人数
|
|
21、列出在部门"SALES"<销售部>工作的员工的姓名,假定不知道销售部的部门编号
。。。。想复杂了,以为是没有deptno字段,那样就没法做到连表了。
|
|
22、列出薪金高于公司平均薪金的所有员工,所在部门,上级领导,雇员的工资等级
|
|
23、列出与"SCOTT"从事相同工作的所有员工及部门名称
|
|
小Tips:要排除SCOTT自己,所以需要加上一个and条件
24、列出薪金等于部门30中员工的薪金的其他员工的姓名和薪金
|
|
25、列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金.部门名称
|
|
小Tips: 不等于可以写成
<>
26、列出在每个部门工作的员工数量,平均工资和平均服务期限
|
|
小Tips:
- 分组函数group,可以有多个字段共同分组。这样在select中就可以查询多个字段
- ifnull(,)这个函数可以把空值替换成想要的值。
- TimeStampDiff(间隔类型,前一个日期,后一个日期)
27、列出所有员工的姓名、部门名称和工资
|
|
28、列出所有部门的详细信息和人数
|
|
小Tips: 在查询部门的数量的时候,一定要使用left join。因为只有dept表中使用了编号为40的部门,而emp表中没有。如果使用join是内连接(交集),就会丢失一个deptno=40的值。这里使用左外连接,leftjoin,取dept表的全集。
29、列出各种工作的最低工资及从事此工作的雇员姓名
|
|
30、列出各个部门的MANAGER(领导)的最低薪金
真坑啊,这里的MANAGER指的是工作岗位。。。
|
|
31、列出所有员工的年工资,按年薪从低到高排序
|
|
32、求出员工领导的薪水超过3000的员工名称与领导名称
|
|
33、求出部门名称中,带’S’字符的部门员工的工资合计、部门人数
|
|
34、给任职日期超过30年的员工加薪10%
|
|
Rows matched: 14 Changed: 14 Warnings: 0