sql语句面试经典题型

目录

案例一:获取每个部门中当前员工薪水最高的相关信息,给出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 <排序用列清单> )

*其中[ ]中的内容可以忽略

猜你喜欢

转载自blog.csdn.net/Promise_J_Z/article/details/121259505