目录
案例一:获取每个部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary,按照部门编号dept_no升序排列
案例二:请你获取薪水第二多的员工的emp_no以及其对应的薪水salary
案例三:请你查找薪水排名第二多的员工编号emp_no、薪水salary、last_name以及first_name,不能使用order by完成
案例四:请你查找在职员工自入职以来的薪水涨幅情况,给出在职员工编号emp_no以及其对应的薪水涨幅growth,并按照growth进行升序
案例五:对所有员工的薪水按照salary降序进行1-N的排名,要求相同salary并列,且按照emp_no升序排列(考察窗口函数)
案例一:获取每个部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary,按照部门编号dept_no升序排列
salaries表结构:
dept_emp表结构
答案:
首先要获取每个部门以及最高的薪资是多少,作为中间表,然后在联立两个表获取emp_no
SELECT
b.dept_no,
b.emp_no,
a.salary
FROM
(
SELECT
a.dept_no,
max( b.salary ) salary
FROM
dept_emp a
LEFT JOIN salaries b ON a.emp_no = b.emp_no
GROUP BY
dept_no
) a
INNER JOIN dept_emp b ON a.dept_no = b.dept_no
INNER JOIN salaries c ON c.salary = a.salary
AND c.emp_no = b.emp_no
ORDER BY
dept_no ASC
建表语句:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for salaries
-- ----------------------------
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`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of salaries
-- ----------------------------
INSERT INTO `salaries` VALUES (10001, 88958, '2002-06-22', '9999-01-01');
INSERT INTO `salaries` VALUES (10002, 72527, '2001-08-02', '9999-01-01');
INSERT INTO `salaries` VALUES (10003, 90000, '2021-11-10', '2021-11-10');
SET FOREIGN_KEY_CHECKS = 1;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for dept_emp
-- ----------------------------
CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`, `dept_no`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of dept_emp
-- ----------------------------
INSERT INTO `dept_emp` VALUES (10001, 'd001', '1986-06-26', '9999-01-01');
INSERT INTO `dept_emp` VALUES (10002, 'd002', '1996-08-03', '9999-01-01');
INSERT INTO `dept_emp` VALUES (10003, 'd002', '2021-11-10', '2021-11-10');
SET FOREIGN_KEY_CHECKS = 1;
案例二:请你获取薪水第二多的员工的emp_no以及其对应的薪水salary
salaries表结构:
答案:
这道题第一眼看上去有些简单,就是有一个小坑,从第一眼感觉上会按照薪水进行倒序排序,然后取第二个,但是薪水第二多的员工可能不止一个!所以我们要先获取倒数第二的薪水是多少,再以薪水为条件找出员工号,但是薪水也是重复的,所以要按照薪水排序之前要么对薪水进行去重,要么按照薪水分组后再排序
SELECT
emp_no,
salary
FROM
salaries
WHERE
salary = ( SELECT distinct salary FROM salaries ORDER BY salary DESC LIMIT 1, 1 )
建表语句:
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`));
INSERT INTO salaries VALUES(10001,88958,'2002-06-22','9999-01-01');
INSERT INTO salaries VALUES(10002,72527,'2001-08-02','9999-01-01');
INSERT INTO salaries VALUES(10003,43311,'2001-12-01','9999-01-01');
案例三:请你查找薪水排名第二多的员工编号emp_no、薪水salary、last_name以及first_name,不能使用order by完成
employees表结构
salaries表结构:
答案:
题目中不允许使用order by,那么思路就是先通过max(salary) 找出薪水最高的薪水,再通过重新查找一次max(salary) 并且当薪水不等于第一个max(salary)的薪水,也就是薪水第二高的薪水,再以此为条件通过inner join 连表查询
SELECT
a.emp_no,
salary,
last_name,
first_name
FROM
employees a
INNER JOIN salaries b ON a.emp_no = b.emp_no
WHERE
salary = ( SELECT max( salary ) FROM salaries WHERE salary != ( SELECT MAX( salary ) FROM salaries ) )
建表语句:
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`));
INSERT INTO employees VALUES(10001,'1953-09-02','Georgi','Facello','M','1986-06-26');
INSERT INTO employees VALUES(10002,'1964-06-02','Bezalel','Simmel','F','1985-11-21');
INSERT INTO employees VALUES(10003,'1959-12-03','Parto','Bamford','M','1986-08-28');
INSERT INTO employees VALUES(10004,'1954-05-01','Chirstian','Koblick','M','1986-12-01');
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`));
INSERT INTO salaries VALUES(10001,88958,'2002-06-22','9999-01-01');
INSERT INTO salaries VALUES(10002,72527,'2001-08-02','9999-01-01');
INSERT INTO salaries VALUES(10003,43311,'2001-12-01','9999-01-01');
INSERT INTO salaries VALUES(10004,74057,'2001-11-27','9999-01-01');
案例四:请你查找在职员工自入职以来的薪水涨幅情况,给出在职员工编号emp_no以及其对应的薪水涨幅growth,并按照growth进行升序
(注: to_date为薪资调整某个结束日期,或者为离职日期,to_date='9999-01-01'时,表示依然在职,无后续调整记录)
employees表结构
salaries表结构
答案:
题目中理解不透彻是存在易错点的,一开始我认为salaries表中已经有了足够的字段作为输出结果,不employees表,最开始的思路是,既然求涨幅,那么只需要按照员工编号分组,分别求出最高工资和最低工资,最高工资的to_date='9999-01-01‘,代表在职,这样两数一减就可以得出涨幅,但是正确的思路不是这样的,因为可能存在薪资负增长的现象,如果拿最低的薪资作为起始薪资,那么涨幅是不正确的,所以要通过入职时间hire_date作为条件找出刚入职的薪资,再通过to_date条件找出最后的薪资才能求出正确的涨幅
SELECT
a.emp_no,
( b.salary - a.salary ) growth
FROM
( SELECT emp_no, salary FROM salaries s
WHERE from_date = (SELECT hire_date FROM employees WHERE emp_no = s.emp_no)
GROUP BY emp_no ) a
INNER JOIN
( SELECT emp_no, salary FROM salaries WHERE to_date = '9999-01-01' GROUP BY emp_no ) b
ON a.emp_no = b.emp_no ORDER BY 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`));
INSERT INTO employees VALUES(10001,'1953-09-02','Georgi','Facello','M','2001-06-22');
INSERT INTO employees VALUES(10002,'1964-06-02','Bezalel','Simmel','F','1999-08-03');
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`));
INSERT INTO salaries VALUES(10001,85097,'2001-06-22','2002-06-22');
INSERT INTO salaries VALUES(10001,88958,'2002-06-22','9999-01-01');
INSERT INTO salaries VALUES(10002,72527,'1999-08-03','2000-08-02');
INSERT INTO salaries VALUES(10002,72527,'2000-08-02','2001-08-02');
案例五:对所有员工的薪水按照salary降序进行1-N的排名,要求相同salary并列,且按照emp_no升序排列(考察窗口函数)
salaries表结构
答案:
这道题主要是利用到了mysql的窗口函数,需要mysql版本达8以上才支持
SELECT emp_no,salary, dense_rank() over(order by salary desc) as t_rank
FROM salaries
WHERE to_date = '9999-01-01'
ORDER BY t_rank, emp_no asc
建表语句:
drop table if exists `salaries` ;
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`));
INSERT INTO salaries VALUES(10001,88958,'2002-06-22','9999-01-01');
INSERT INTO salaries VALUES(10002,72527,'2001-08-02','9999-01-01');
INSERT INTO salaries VALUES(10003,43311,'2001-12-01','9999-01-01');
INSERT INTO salaries VALUES(10004,72527,'2001-12-01','9999-01-01');
下面介绍三种用于进行排序的专用窗口函数:
1、RANK()
在计算排序时,若存在相同位次,会跳过之后的位次。
例如,有3条排在第1位时,排序为:1,1,1,4······
2、DENSE_RANK()
这就是题目中所用到的函数,在计算排序时,若存在相同位次,不会跳过之后的位次。
例如,有3条排在第1位时,排序为:1,1,1,2······
3、ROW_NUMBER()
这个函数赋予唯一的连续位次。
例如,有3条排在第1位时,排序为:1,2,3,4······
窗口函数用法:
<窗口函数> OVER ( [PARTITION BY <列清单> ]
ORDER BY <排序用列清单> )
*其中[ ]中的内容可以忽略