牛客网SQL实战二刷 | Day4

「牛客网SQL实战二刷」是个系列学习笔记博文,每天解析6道SQL题目~ 今天是第19-24题~

每篇笔记的格式大致为,三大板块:

  • 大纲
  • 题目(题目描述、思路、代码、相关参考资料/答疑)
  • 回顾

一、大纲

题号 知识点
19 LEFT JOIN
20 SELECT 嵌套
21 SELECT 嵌套
22 GROUP BY, COUNT()
23 表的复用,DISTINCT,ORDER BY,GROUP BY
24 NOT IN

二、题目

19. 查找所有员工的last_name和first_name以及对应的dept_name

  • 题目描述

查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工
CREATE TABLE departments (
dept_no char(4) NOT NULL,
dept_name varchar(40) NOT NULL,
PRIMARY KEY (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));

  • 输出描述
last_name first_name dept_name
Facello Georgi Marketing
省略 省略 省略
Sluis Mary NULL
  • 思路
  1. 第一次LEFT JOIN employees表和dept_emp表,得到last_name 和first_name;
  2. 第二次LEFT JOIN departments表,得到dept_name;
  3. 因为查找所有员工,「也包括暂时没有分配部门的员工」,所以用LEFT JOIN。
  • 代码
SELECT e.last_name, e.first_name, d.dept_name
FROM employees AS e LEFT JOIN dept_emp AS de ON e.emp_no = de.emp_no
LEFT JOIN departments AS d ON de.dept_no = d.dept_no

20.查找员工编号emp_no为10001其自入职以来的薪水salary涨幅值growth

  • 题目描述

查找员工编号emp_no为10001其自入职以来的薪水salary涨幅值growth
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));

  • 输出描述
growth
28841
  • 思路
    分别找到emp_no为10001员工当前薪水和入职薪水,做差即为growth

  • 代码

SELECT (
(SELECT salary FROM salaries WHERE emp_no = 10001 ORDER BY to_date DESC LIMIT 1 ) - 
(SELECT salary FROM salaries WHERE emp_no = 10001 ORDER BY from_date ASC LIMIT 1)
)AS growth

21. 查找所有员工自入职以来的薪水涨幅情况

  • 题目描述

查找所有员工自入职以来的薪水涨幅情况,给出员工编号emp_no以及其对应的薪水涨幅growth,并按照growth进行升序
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));

  • 输出描述
emp_no growth
10011 0
省略 省略
54496 10004
  • 思路

  • 产生两张表,一张记录当前薪水,一张记录入职薪水;

  • 用emp_no连接两张表,对应salary做差表示growth。

  • 代码

SELECT sCurrent.emp_no, (sCurrent.salary - sStart.salary) AS growth
FROM (SELECT e.emp_no, s.salary FROM employees AS e, salaries AS s WHERE e.emp_no = s.emp_no AND s.to_date = '9999-01-01') AS sCurrent,
(SELECT e.emp_no, s.salary FROM employees AS e, salaries AS s WHERE e.emp_no = s.emp_no AND e.hire_date = s.from_date) AS sStart
WHERE sCurrent.emp_no = sStart.emp_no
ORDER BY growth

22. 统计各个部门对应员工涨幅的次数总和

  • 题目描述

统计各个部门对应员工涨幅的次数总和,给出部门编码dept_no、部门名称dept_name以及次数sum
CREATE TABLE departments (
dept_no char(4) NOT NULL,
dept_name varchar(40) NOT NULL,
PRIMARY KEY (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 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));

  • 输出描述
dept_no dept_name sum
d001 Marketing 24
d002 Finance 14
d003 Human Resources 13
d004 Production 24
d005 Development 25
d006 Quality Management 25
  • 思路
  • 先连接dept_emp表和salaries表,得到dept_no和emp_no;
  • 再连接departments表,得到dept_name ;
  • 用GROUP BY按照dept_no分组,用COUNT()计数。
  • 代码
SELECT de.dept_no, d.dept_name, COUNT(s.emp_no) AS sum
FROM (dept_emp AS de INNER JOIN salaries AS s ON de.emp_no = s.emp_no)
    INNER JOIN departments AS d ON de.dept_no = d.dept_no
GROUP BY de.dept_no

23. 对所有员工的薪水按照salary进行按照1-N的排名

  • 题目描述

对所有员工的当前(to_date=‘9999-01-01’)薪水按照salary进行按照1-N的排名,相同salary并列且按照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));

  • 输出描述
emp_no salary rank
10005 94692 1
10009 94409 2
10010 94409 2
10001 88958 3
10007 88070 4
10004 74057 5
10002 72527 6
10003 43311 7
10006 43311 7
10011 25828 8
  • 思路
  1. 复用salaries表进行排名比较;
  2. rank即为第二张表中有多少大于等于当前salary的个数,由于并列排名,应当使用DISTINCT去重;
  3. 按照emp_no分组;
  4. 按照salary逆序和emp_no升序排列。
  • 代码
SELECT s1.emp_no, s1.salary, COUNT(DISTINCT s2.salary) AS rank
FROM salaries AS s1, salaries AS s2
WHERE s1.to_date = '9999-01-01' AND s2.to_date = '9999-01-01' AND s1.salary <= s2.salary
GROUP BY s1.emp_no
ORDER BY s1.salary DESC, s1.emp_no

24.获取所有非manager员工当前的薪水情况

  • 题目描述

获取所有非manager员工当前的薪水情况,给出dept_no、emp_no以及salary ,当前表示to_date=‘9999-01-01’
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 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));
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));

  • 输出描述
dept_no emp_no salary
d001 10001 88958
d004 10003 43311
d005 10007 88070
d006 10009 95409
  • 思路
  1. 连接dept_emp表和salaries表得到dept_no,emp_no和salary
  2. 「所有非manager员工」,因此要排除dept_manager表中的员工emp_no
  • 代码
SELECT de.dept_no, de.emp_no, s.salary
FROM dept_emp AS de INNER JOIN salaries AS s ON de.emp_no = s.emp_no AND s.to_date = '9999-01-01'
WHERE de.emp_no NOT IN (SELECT emp_no FROM dept_manager)

三、回顾

知识点 题号
LEFT JOIN 19
ORDER BY 23
表的复用 23
DISTINCT 23
NOT IN 24
函数 22「COUNT()」
SELECT 嵌套 20, 21
GROUP BY 22, 23

猜你喜欢

转载自blog.csdn.net/weixin_44915703/article/details/94041842