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

1. 查找最晚入职员工的所有信息

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));

解题思路:根据入职时间倒序排序order by ... DESC,然后再取一条记录,就是最晚入职的员工。

select * from employees 
order by hire_date DESC limit 1;

这样做有一个问题,hire_date是 date 类型,很有可能多条记录中是同一个时间入职的,所以说时间类型还是用时间戳比较精切。

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

针对这道题目可以使用 MAX() 函数,然后用一个子查询。

select * from employees
where hire_date = (select MAX(hire_date) FROM employees);

MAX()先查询出最晚入职的时间,然后再查询出在最晚时间入职的所有员工。


2. 查找入职员工时间排名倒数第三的员工所有信息

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

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));

解题思路:查询入职时间倒数第三的,要先进行排序,再取三条记录。MySQL中的结果集默认以正序排列,要逆序排列就要使用 DESC,取第三条则是使用limit

select * from employees
order by hire_date DESC 
limit 2,1;

3. 查找当前薪水详情以及部门编号dept_no

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

CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));

CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));

解题思路:这是一个等值连接的题目,用员工编号emp_no 做关联即可。

select s.*, d.dept_no
from salaries s
join dept_manager d on d.emp_no = s.emp_no
where d.to_date='9999-01-01';

上面的SQL有一个优化的点,就是可以用 s.to_date='9999-01-01' 再进行一次去重锁定。修改之后的 SQL 如下所示:

select s.*, d.dept_no
from salaries s
join dept_manager d on d.emp_no = s.emp_no
where d.to_date='9999-01-01'  and s.to_date='9999-01-01';

吐槽:牛客网里,表 dept_manager 用两个字母的别名 dm,竟然过不了...


4. 查找所有已经分配部门的员工的last_name和first_name以及dept_no

查找所有已经分配部门的员工的last_name和first_name以及dept_no

CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));

解题思路:这道题开始想到用一个子查询,先查询出所有部门id,作为条件去查询员工表。然后看到还需要查询出部门表里的dept_no ,所以觉得用外连接更加合适,用dept_emp 表作为主表进行查询。

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

5. 查找所有员工的last_name和first_name以及对应部门编号dept_no

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

CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));

解题思路:这个和上一题一个意思,只是这题里,没有部门号的也要查询出来,即查询所有员工,以员工表作为主表。

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

6. 查找所有员工入职时候的薪水情况

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

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));

CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));

解题思路:这道题要考虑到,员工的入职时的薪水情况,即他入职第一个月时的薪水,即employees.​hire_date=salaries.​from_date​​

select e.emp_no, s.salary
from employees e
join salaries s on e.emp_no=s.emp_no and e.hire_date = s.from_date
order by e.emp_no DESC;

7. 查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t

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

CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`)
);

解题思路:看到这道题第一反应是,这道题也太复杂了。因为薪水涨幅需要比较前后两个月的薪水,如果薪水下降是不能算涨幅的。所以,用解题的思路,我觉得这道题不会这么复杂,就大胆假设它默认一直涨薪的。

从应试的角度,我觉得它是要考察 group by...having...,也就是先通过 emp_no 进行分组,再过滤分组记录数大于15的记录

select emp_no, count(emp_no) as t
from salaries
group by emp_no
having t > 15;

果然是这样。不用纠结这道题的题意,知道考察点在group by...having...就行了。

MySQL having子句


8. 找出所有员工当前薪水salary情况

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

CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));

解题思路:这道题讲到了,相同的薪水只显示一次,就是让我们用 DISTINCT 去重。

select DISTINCT salary
from salaries
where to_date='9999-01-01'
order by salary DESC;

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

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

CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));

CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));

解题思路:这道题先看表结构,emp_no,dept_nodept_manager 表的主键,这就表示一个部门可能有多个领导,然后dept_manager 去关联salaries 表查询工资即可,限制条件是查询当天的工资 s.to_date='9999-01-01';

select d.dept_no, d.emp_no, s.salary
from dept_manager d
join salaries s on d.emp_no = s.emp_no
where s.to_date='9999-01-01';

但是我这样写,竟然AC不过,导入数据后发现,查询结果是这样的,意思就是一个部门的一个领导,在同一天会有多份工资??

d001	10002	72527
d001	10002	72527
d001	10002	72527
d001	10002	72527
d001	10002	72527
d001	10002	72527
d004	10004	40054
d004	10004	42283
d004	10004	42542
d004	10004	46065
d004	10004	48271
d004	10004	50594
d004	10004	52119
d004	10004	54693
d004	10004	58326

要再加一个查询条件d.to_date='9999-01-01',看讨论说是表示在职的经理。

select d.dept_no, d.emp_no, s.salary
from dept_manager d
join salaries s on d.emp_no = s.emp_no
where s.to_date='9999-01-01' and d.to_date='9999-01-01';

10. 获取所有非manager的员工emp_no

获取所有非manager的员工emp_no

CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));

解题思路:查找不是 Manager 的员工,即 employees 左连接 dept_manager 之后,没有在 dept_manager 表中查询到记录的员工。所以在关联之后,判断 d.dept_no IS NULL; 就是在 dept_manager 表中没有数据的员工了。

select e.emp_no
from employees e
left join dept_manager d on e.emp_no = d.emp_no
where d.dept_no IS NULL;

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