牛客网数据库SQL实战详细剖析(1-10)

牛客网数据库SQL实战详细剖析(1-10)_第1张图片

本文授权转载自大数据肌肉猿

禁止二次转载

大家好,我是老表

阅读文本大概需要 11 分钟

这是一个系列文章,总共61题,分6期,有答案以及解题思路,并附上解题的一个思考过程。

具体题目可参考牛客网的SQL实战模块:

https://www.nowcoder.com/ta/sql?page=0

第一题:查找最晚入职员工的所有信息

select * from employeeswhere hire_date = (select max(hire_date) from employees);

解题思路:使用子查询的方法,先找出所有入职时间里最大(即最晚)的时间,这样可以确保多条最晚入职时间都可以被查询出来。

有使用order by 按由大到小排序后选取第一条的方法,但这种方法仅限于当最晚入职数据只有一条时才正确,不能保证有多条同一最晚时间时的准确性。

select * from employeesorder by hire_date desclimit 1;

第二题:查找入职员工时间排名倒数第三的员工所有信息

select * from employeeswhere hire_date = (select distinct hire_date from employeesorder by hire_date desc limit 2,1);

解题思路:同样使用子查询方法,关键是要用distinct去重,去重后会按入职日期进行分组,多个相同入职日期会分为一组。

第一次做的方法:

select * from employeesorder by hire_date desc limit 2,1;

这个查询没有去重,只能查出入职时间排名三的时间的员工信息,而不是入职员工时间排名倒数第三的员工的入职时间。

第三题:查找各个部门当前(to_date='9999-01-01')领导当前薪水详情以及其对应部门编号dept_no

select s.*,d.dept_nofrom salaries s join dept_manager d on s.emp_no = d.emp_nowhere d.to_date = '9999-01-01' and s.to_date = '9999-01-01';

解题思路:以s.emp_no = d.emp_no为联结条件联结两表,同时限制两表to_date = '9999-01-01'(原因:去重锁定)

第四题:查找所有已经分配部门的员工的last_name和first_name

select e.last_name,e.first_name,d.dept_nofrom employees e left join dept_emp d on e.emp_no = d.emp_nowhere d.dept_no is not null;

解题思路:employees作为主表,使用左联结,关键是where d.dept_no is not null;题目要查找所有已经分配部门的员工,意味着必须要带有dept_no,没有dept_no的就是还未分配部门的,去除dept_no为空即可求得。

第五题:查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工

select e.last_name,e.first_name,d.dept_nofrom employees e left join dept_emp d on e.emp_no = d.emp_no;

解题思路:employees作为主表,使用左联结,比较简单。

第六题:查找所有员工入职时候的薪水情况,给出emp_no以及salary, 并按照emp_no进行逆序

select e.emp_no,s.salaryfrom salaries s left join employees e on s.emp_no = e.emp_nowhere e.hire_date = s.from_dateorder by s.emp_no desc;

解题思路:使用左联结(内联结也可以),此题最关键的是salaries表的from_date 和 employees表的hire_date 的值应该要相等,因此有限制条件e.hire_date = s.from_date,两个date都是刚入职的时间,一开始我就是搞不清这个逻辑关系,一个劲想用min(from_date)求出。

另外,salaries表中有多个相同emp_no的salary,即emp_no在salaries表中不唯一,仔细查看时间和工资,推断出是同一员工在不同时间的工资不同,即涨薪或降薪(具体涨薪或降薪没有一个个查看),理解这两个关键点解题就没问题了。

第七题:查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t

select a.emp_no,count(*) tfrom salaries a inner join salaries b on a.emp_no=b.emp_no and a.to_date = b.from_datewhere a.salary < b.salarygroup by a.emp_nohaving t > 15;

解题思路:count(*) 为计算全部数据的行数地意思,比较关键的一个点就是联结条件a.to_date = b.from_date,这个条件限定了两个工资之比必须是相邻的,如果没有这个条件,那同一个emp_no下的任意两个salary都可以做对比,可以把这个条件去掉,对比两个查询结果,就明白了。

验证查询:创建表sa,表信息如下:

牛客网数据库SQL实战详细剖析(1-10)_第2张图片

计算涨薪次数查询代码:

select a.emp_no,count(*) tfrom sa a inner join sa b on a.emp_no=b.emp_no and a.to_date = b.from_datewhere a.salary < b.salarygroup by a.emp_no;

结果:

验证无误,但还是有一个小问题,这个查询结果仅以后一次工资跟前一次工资对比,只要比前一次工资高,就算一次涨薪,而不与这“后一次”工资跟前一次之前的工资数据相比。

例如:

牛客网数据库SQL实战详细剖析(1-10)_第3张图片

在原来数据的基础上增加两条数据,工资为1和3,这个数据查询出的涨薪次数就是4。

这条题目比较有争议,题意不清晰。以下是我找到正确答案之前的尝试:

方法一:

select emp_no,count(salary) as tfrom salariesgroup by emp_nohaving t > 16;

但是这个会有一个问题,它只查询工资出现次数的计数,不管是加薪、降薪还是工资不变的所有情况,都会被计算进去。

方法二:

select emp_no,count(distinct salary) as tgroup by emp_nohaving t > 16;

这个也有问题,这只能计算出在没有降薪的情况下的涨薪次数,后面如果有降薪的话,就会出错。

(这两个方法都选择大于16的条件限定的原因:都是以工资出现次数为计算涨薪的,把第一次工资也计算进去了,实际上第一次工资不能纳入涨薪次数中去,所以用大于16来限定条件,达到符合题目要求的涨薪大于15次目的)

第八题:找出所有员工当前(to_date='9999-01-01')具体的薪水salary情况,对于相同的薪水只显示一次,并按照逆序显示

select salaryfrom salarieswhere to_date='9999-01-01'group by salaryorder by salary desc;

解题思路:关键理解对于相同的薪水只显示一次,使用分组方法对salary进行分组求得,也可以使用distinct去重的方法,但是一般数据较多时使用distinct效率相比group by 要慢,所以从性能角度考虑,应该尽量使用group by。

使用distinct方法如下:

select distinct salaryfrom salarieswhere to_date='9999-01-01'order by salary desc;

第九题:获取所有部门当前manager的当前薪水情况,给出dept_no, emp_no以及salary,当前表示to_date='9999-01-01'

SELECT d.dept_no,d.emp_no,s.salaryfrom salaries s left join dept_manager d on d.emp_no = s.emp_nowhere d.to_date = '9999-01-01' and s.to_date = '9999-01-01';

解题思路:关键点是dept_manager表的to_date和salaries表的to_date都要等于'9999-01-01',s.to_date = '9999-01-01'容易理解,限定当前时间当前工资,d.to_date = '9999-01-01'则限定在职经理,注意理解题目,有两个“当前”。

第十题:获取所有非manager的员工emp_no

select e.emp_nofrom employees e left join dept_manager d on e.emp_no = d.emp_nowhere d.dept_no is null;

解题思路:employees作为主表,使用左联结,限定条件为d.dept_no为空,选出在employees但不在dept_manager中的emp_no记录。

大家好,我是老表
觉得本文不错的话,转发、留言、点赞,是对我最大的支持。

欢迎关注微信公众号:简说Python关注后回复:1024,可以领取学习资源。

每日留言

说说你读完本文感受?

或者一句激励自己的话?

(字数不少于15字)

怎么加入习队

点我,看文末彩蛋

留言有啥福利

点我就知道了

想进学习交流

微信jjxksa888

:简说Python

既然大家非主流还用

2小时快速掌握Python基础知识要点

完整Python基础知识要点

Python小知识 | 这些技能你不会?(一)

Python小知识 | 这些技能你不会?(二)

Python小知识 | 这些技能你不会?(三)

Python小知识 | 这些技能你不会?(四)

你可能感兴趣的:(牛客网数据库SQL实战详细剖析(1-10))