SQL数据库实战题_面试必刷+解析_牛客题霸_牛客网 (nowcoder.com)
SQL1 查找最晚入职员工的所有信息
1 | # 方法1:使用子查询 |
SQL2 查找入职员工时间排名倒数第三的员工所有信息
可能有入职时间相同的员工,所以利用 SELECT DISTINCT
语句,仅仅列出不同(distinct)的值。
1 | SELECT * FROM employees |
SQL3 查找各个部门当前领导当前薪水详情以及其对应部门编号dept_no
WHERE
的两个条件是确保还在职,通过 SELECT s.*, d.dept_no
提取出我们需要的列。
1 | SELECT s.*, d.dept_no FROM salaries s INNER JOIN dept_manager d |
SQL4 查找所有已经分配部门的员工的last_name和first_name以及dept_no
用内连接
1 | SELECT e.last_name,e.first_name,d.dept_no FROM employees e |
SQL5 查找所有员工的last_name和first_name以及对应部门编号dept_no
观察输出要求,很明显我们要用到的是左外连接,输出全部左表内容,右表没有的用 null 替代。
1 | SELECT e.last_name, e.first_name,d.dept_no |
SQL7 查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t
1、用 COUNT() 函数和 GROUP BY 语句可以统计同一 emp_no 值的记录条数
2、根据题意,输出的变动次数为 t,故用 AS 语句将 COUNT(emp_no) 的值转换为 t
3、由于 COUNT() 函数不可用于 WHERE 语句中,故使用 HAVING 语句来限定 t>15 的条件
1 | SELECT emp_no, COUNT(emp_no) AS t FROM salaries GROUP BY emp_no HAVING COUNT(emp_no) > 15; |
SQL8 找出所有员工当前具体的薪水salary情况
对于 DISTINCT 与 GROUP BY 的使用:
- 当对系统的性能高并且数据量大时使用 GROUP BY
- 当对系统的性能不高时或者使用数据量少时两者皆可
- 尽量使用 GROUP BY
1 | # 方法1:DISTINCT |
SQL10 获取所有非manager的员工emp_no
IN 关键字适合确定数量的情况,一般效率较低。能用 IN 关键字的语句都可以转化为使用 JOIN 的语句,推荐使用 JOIN。
1 | # 方法一:使用NOT IN选出在employees但不在dept_manager中的emp_no记录 |
SQL11 获取所有员工当前的manager
1、用 INNER JOIN 连接两张表,因为要输出自己的经理,得知自己与经理的部门要相同,故有限制条件 de.dept_no = dm.dept_no
2、再用 WHERE 限制当前员工与当前经理的条件,即 dm.to_date='9999-01-01'
、de.to_date='9999-01-01'
、de.emp_no<>dm.emp_no
3、为了增强代码可读性,将 dept_emp 用别名 de 代替,dept_manager 用 dm 代替,最后根据题意将 de.emp_no 用别名 manager_no 代替后输出
1 | SELECT de.emp_no, dm.emp_no manager FROM dept_emp de INNER JOIN dept_manager dm |
SQL12 获取每个部门中当前员工薪水最高的相关信息
这个题挺难的,理解不了就跳过吧,别浪费时间。
思路:在子表中查找部门编号 dept_no 等于主表中部门编号 dept_no 的最大薪水,然后主表的 WHERE 条件限制
1 | SELECT d.dept_no, d.emp_no, s.salary maxSalary |
SQL15 查找employees表
emp_no 为奇数,用位运算可能会快一些。
1 | SELECT * FROM employees |
SQL16 统计出当前各个title类型对应的员工当前薪水对应的平均工资
AVG(*)
是自动命名为 avg 的,所以不用重命名
1 | SELECT t.title, AVG(s.salary) FROM titles t INNER JOIN salaries s |
SQL17 获取当前薪水第二多的员工的emp_no以及其对应的薪水salary
同一薪水可能有多人,所以需要用 GROUP BY
来对 salary 分组或者 DISTINCT
来对 salary 去重,得到第二高的薪水,然后主表再用 WHERE
进行查询。
1 | SELECT emp_no, salary FROM salaries |
SQL18 获取当前薪水第二多的员工的emp_no以及其对应的薪水salary
题目要求不能使用 ORDER BY
,那么只能曲线救国了,先查出原表的最高工资,然后查出了原表的最高工资以外的最高工资(即第二高工资),然后根据该条件去查出薪水第二多的员工信息。
1 | SELECT s.emp_no,s.salary,e.last_name,e.first_name |
方法二,也是模板方法 评论区里的答案详解_牛客博客 (nowcoder.net)
因为是按照 s1.salary <= s2.salary
来连接的,按照 s1.salary 分组后,一个 s1.salary 对应 1 个或多个大于等于它的 s2.salary。假设没有重复,如果 s1.salary=MAX(salary)
那么它就只对应一个 s2.salary,即最大的那个值。如果 s1.salary 是第二大的,那么它对应的就有 2 个 s2.salary,即最大的和第二大的。于是我们可以利用 HAVING COUNT(s2.salary)=n
来找到第 n 大的 salary。那么在有重复的情况下,我们只需要加上 DISTINCT
来对每一组数据进行去重就满足条件了。
1 | select s.emp_no, s.salary, e.last_name, e.first_name |
表自连接以后:
s1 | s2 |
---|---|
100 | 100 |
98 | 98 |
98 | 98 |
95 | 95 |
当s1<=s2链接并以s1.salary分组时一个s1会对应多个s2
s1 | s2 |
---|---|
100 | 100 |
98 | 100 |
98 | |
98 | |
95 | 100 |
98 | |
98 | |
95 |
对s2进行去重统计数量, 就是s1对应的排名
SQL19 查找所有员工的last_name和first_name以及对应的dept_name
先内连接 departments 表和 dept_emp 表形成新表 t,再左连接 employees 表和 t 表
1 | SELECT e.last_name, e.first_name, t.dept_name FROM employees e LEFT JOIN ( |
先左连接 employees 表和 dept_emp表,根据 emp_no 来确定每个员工的部门 dept_no,然后再左连接 departments 表,根据 dept_no 来确定所对应的的部门名称。
1 | SELECT last_name, first_name, dept_name |
SQL21 查找在职员工自入职以来的薪水涨幅情况
1 | SELECT s1.emp_no, s2.salary-s1.salary AS growth |
SQL22 统计各个部门的工资记录数
三表联查
1 | SELECT d.dept_no, d.dept_name, COUNT(*) AS sum |
SQL23 对所有员工的当前薪水按照salary进行按照1-N的排名
SQL窗口函数。通俗易懂的学会:SQL窗口函数 - 知乎 (zhihu.com)
1 | SELECT emp_no, salary, dense_rank() OVER (ORDER BY salary DESC) AS t_rank FROM salaries |
sql24 获取所有非manager员工当前的薪水情况
先去 dept_manager 表中找到所有经理的 emp_no,然后内连接 employees 表和 dept_emp 表查询不是经理的所有员工,令结果为新表 t1。
然后把新表 t1 和 salaries 表内连接查询结果。
1 | SELECT |