动力节点 mysql 郭鑫 34道经典的面试题
DROP TABLE IF EXISTS `dept`; CREATE TABLE `dept` ( `DEPTNO` int(2) NOT NULL COMMENT '部门编号', `DNAME` varchar(14) DEFAULT NULL COMMENT '部门名称', `LOC` varchar(13) DEFAULT NULL COMMENT '位置', PRIMARY KEY (`DEPTNO`) ) ENGINE=InnoDB;
INSERT INTO `dept` VALUES ('10', 'ACCOUNTING', 'NEW YORK'); INSERT INTO `dept` VALUES ('20', 'RESEARCH', 'DALLAS'); INSERT INTO `dept` VALUES ('30', 'SALES', 'CHICAGO'); INSERT INTO `dept` VALUES ('40', 'OPERATIONS', 'BOSTON');
创建员工表
DROP TABLE IF EXISTS `emp`; CREATE TABLE `emp` ( `EMPNO` int(4) NOT NULL COMMENT '员工编号', `ENAME` varchar(10) DEFAULT NULL COMMENT '员工姓名', `JOB` varchar(9) DEFAULT NULL COMMENT '工作岗位', `MGR` int(4) DEFAULT NULL COMMENT '上级经理', `HIREDATE` date DEFAULT NULL, `SAL` double(7,2) DEFAULT NULL, `COMM` double(7,2) DEFAULT NULL, `DEPTNO` int(2) DEFAULT NULL, PRIMARY KEY (`EMPNO`), KEY `DEPTNO` (`DEPTNO`), KEY `SAL` (`SAL`), CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`DEPTNO`) REFERENCES `dept` (`DEPTNO`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='员工编号';
插入语句:
INSERT INTO `emp` VALUES ('7369', 'SMITH', 'CLERK', '7902', '1980-12-17', '800.00', null, '20'); INSERT INTO `emp` VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', '1981-02-20', '1600.00', '300.00', '30'); INSERT INTO `emp` VALUES ('7521', 'WARD', 'SALESMAN', '7698', '1981-02-22', '1250.00', '500.00', '30'); INSERT INTO `emp` VALUES ('7566', 'JONES', 'MANAGER', '7839', '1981-04-02', '2975.00', null, '20'); INSERT INTO `emp` VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', '1981-09-28', '1250.00', '1400.00', '30'); INSERT INTO `emp` VALUES ('7698', 'BLAKE', 'MANAGER', '7839', '1981-05-01', '2850.00', null, '30'); INSERT INTO `emp` VALUES ('7782', 'CLARK', 'MANAGER', '7839', '1981-06-09', '2450.00', null, '10'); INSERT INTO `emp` VALUES ('7788', 'SCOTT', 'ANALYST', '7566', '1987-04-19', '3000.00', null, '20'); INSERT INTO `emp` VALUES ('7839', 'KING', 'PRESIDENT', null, '1981-11-17', '5000.00', null, '10'); INSERT INTO `emp` VALUES ('7844', 'TURNER', 'SALESMAN', '7698', '1981-09-08', '1500.00', '0.00', '30'); INSERT INTO `emp` VALUES ('7876', 'ADAMS', 'CLERK', '7788', '1981-05-23', '1100.00', null, '20'); INSERT INTO `emp` VALUES ('7900', 'JAMES', 'CLERK', '7698', '1981-12-03', '950.00', null, '30'); INSERT INTO `emp` VALUES ('7902', 'FORD', 'ANALYST', '7566', '1981-12-03', '3000.00', null, '20'); INSERT INTO `emp` VALUES ('7934', 'MILLER', 'CLERK', '7782', '1982-01-23', '1300.00', null, '10');
C:薪水等级表
1,建表语句
DROP TABLE IF EXISTS `salgrade`; CREATE TABLE `salgrade` ( `GRADE` int(11) DEFAULT NULL, `LOSAL` int(11) DEFAULT NULL, `HISAL` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `salgrade` VALUES ('1', '700', '1200'); INSERT INTO `salgrade` VALUES ('2', '1201', '1400'); INSERT INTO `salgrade` VALUES ('3', '1401', '2000'); INSERT INTO `salgrade` VALUES ('4', '2001', '3000'); INSERT INTO `salgrade` VALUES ('5', '3001', '9999');
表的结构如下所示:
1.取得每个部门最高薪水的人员名称
第一步:求出每个部门的最高薪水 select e.deptno,max(e.sal) as maxsal from emp e group by e.deptno; +--------+---------+ | deptno | maxsal | +--------+---------+ | 10 | 5000.00 | | 20 | 3000.00 | | 30 | 2850.00 | +--------+---------+ 将以上查询结果当成一个临时表t(deptno,maxsal) select e.deptno,e.ename,t.maxsal,e.sal from (select e.deptno,max(e.sal) as maxsal from emp e group by e.deptno)t join emp e on t.deptno = e.deptno where t.maxsal = e.sal order by e.deptno; +--------+-------+---------+---------+ | deptno | ename | maxsal | sal | +--------+-------+---------+---------+ | 10 | KING | 5000.00 | 5000.00 | | 20 | SCOTT | 3000.00 | 3000.00 | | 20 | FORD | 3000.00 | 3000.00 | | 30 | BLAKE | 2850.00 | 2850.00 | +--------+-------+---------+---------+
分析下:
首先group by 首先经常和聚合函数max等配合使用,第二使用了group by 在select后面的查询字段只能是group by 后面指定的字段不能是其他字段
第三:join on 条件中 on 和where的却别,不清楚的看自己的博客
MYSQL LEFT JOIN操作中 ON与WHERE放置条件的区别
on是两个表联合查询连接起来生成一个临时表,where是在生成临时表的基础上,对生成的临时表进行条件帅选
t.deptno = e.deptno 表示两个表生成临时表的关系是 emp表中的部门编号必须等于 t表中的部门编号
where之后的条件是:emp表和t表已经生成了临时表,然后对临时表进行条件过滤
2.哪些人的薪水在部门平均薪水之上
2.哪些人的薪水在部门平均薪水之上 第一步:求出每个部门的平均薪水 select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno; +--------+-------------+ | deptno | avgsal | +--------+-------------+ | 10 | 2916.666667 | | 20 | 2175.000000 | | 30 | 1566.666667 | +--------+-------------+ 将以上查询结果当成临时表t(deptno,avgsal) select t.deptno,e.ename from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t join emp e on e.deptno = t.deptno where e.sal > t.avgsal; +--------+-------+ | deptno | ename | +--------+-------+ | 30 | ALLEN | | 20 | JONES | | 30 | BLAKE | | 20 | SCOTT | | 10 | KING | | 20 | FORD | +--------+-------+
3.取得部门中(所有人的)平均薪水等级
第一种情况:emp表中按照部门进行分组,求出每个组的平均工资,看每个组的平均工资属于那个等级
第一步:求出部门的平均薪水 select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno; 将以下查询结果当成临时表t(deptno,avgsal) +--------+-------------+ | deptno | avgsal | +--------+-------------+ | 10 | 2916.666667 | | 20 | 2175.000000 | | 30 | 1566.666667 | +--------+-------------+ select * from salgrade; +-------+-------+-------+ | GRADE | LOSAL | HISAL | +-------+-------+-------+ | 1 | 700 | 1200 | | 2 | 1201 | 1400 | | 3 | 1401 | 2000 | | 4 | 2001 | 3000 | | 5 | 3001 | 9999 | +-------+-------+-------+ select t.deptno,t.avgsal,s.grade from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t join salgrade s on t.avgsal between s.losal and s.hisal; +--------+-------------+-------+ | deptno | avgsal | grade | +--------+-------------+-------+ | 30 | 1566.666667 | 3 | | 10 | 2916.666667 | 4 | | 20 | 2175.000000 | 4 | +--------+-------------+-------+
第二种情况:首先求出每个人的薪水属于那个等级,然后进行分组
3.2 取得部门中所有人的平均的薪水等级 第一步:求出每个人的薪水等级 select e.deptno,e.ename,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal order by e.deptno; +--------+--------+-------+ | deptno | ename | grade | +--------+--------+-------+ | 10 | CLARK | 4 | | 10 | MILLER | 2 | | 10 | KING | 5 | | 20 | ADAMS | 1 | | 20 | SMITH | 1 | | 20 | FORD | 4 | | 20 | SCOTT | 4 | | 20 | JONES | 4 | | 30 | BLAKE | 4 | | 30 | JAMES | 1 | | 30 | ALLEN | 3 | | 30 | WARD | 2 | | 30 | TURNER | 3 | | 30 | MARTIN | 2 | +--------+--------+-------+ 将以上查询结果当成临时表t(deptno,ename,grade) select t.deptno,avg(t.grade) as avgGrade from (select e.deptno,e.ename,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal) t group by t.deptno; +--------+----------+ | deptno | avgGrade | +--------+----------+ | 10 | 3.6667 | | 20 | 2.8000 | | 30 | 2.5000 | +--------+----------+
4.不准用组函数(MAX),取得最高薪水(给出两种解决方案) select sal from emp order by sal desc limit 1;
5.取得平均薪水最高的部门的部门编号
5.取得平均薪水最高的部门的部门编号 第一步:求出部门平均薪水 select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno; +--------+-------------+ | deptno | avgsal | +--------+-------------+ | 10 | 2916.666667 | | 20 | 2175.000000 | | 30 | 1566.666667 | +--------+-------------+ 第二步:将以上查询结果当成临时表t(deptno,avgsal),求出最高的平均薪水 select max(t.avgsal) as maxAvgSal from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t; +-------------+ | maxAvgSal | +-------------+ | 2916.666667 | +-------------+ select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno having avgsal = (select max(t.avgsal) as maxAvgSal from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t); +--------+-------------+ | deptno | avgsal | +--------+-------------+ | 10 | 2916.666667 | +--------+-------------+
主要这里有一个坑不能写成下面的形式:
select e.deptno,avg(e.sal) avgSal from emp e group by e.deptno order by avgSal desc limit 1;
因为如果有100个部门,可能存在很多个部门的平均值都是一样的
6.取得平均薪水最高的部门的部门名称 select e.deptno,d.dname,avg(e.sal) as avgsal from emp e join dept d on e.deptno = d.deptno group by e.deptno,d.dname having avgsal = (select max(t.avgsal) as maxAvgSal from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t); 7.求平均薪水的等级最低的部门的部门名称 第一步:部门的平均薪水 select e.deptno,d.dname,avg(e.sal) as avgsal from emp e join dept d on e.deptno = d.deptno group by e.deptno,d.dname; +--------+------------+-------------+ | deptno | dname | avgsal | +--------+------------+-------------+ | 10 | ACCOUNTING | 2916.666667 | | 20 | RESEARCH | 2175.000000 | | 30 | SALES | 1566.666667 | +--------+------------+-------------+ 第二步:将以上结果当成临时表t(deptno,avgsal)与salgrade表进行表连接:t.avgsal between s.losal and s.hisal; select t.deptno,t.dname,s.grade from (select e.deptno,d.dname,avg(e.sal) as avgsal from emp e join dept d on e.deptno = d.deptno group by e.deptno,d.dname)t join salgrade s on t.avgsal between s.losal and s.hisal; +--------+------------+-------+ | deptno | dname | grade | +--------+------------+-------+ | 30 | SALES | 3 | | 10 | ACCOUNTING | 4 | | 20 | RESEARCH | 4 | +--------+------------+-------+ 第三步:将以上查询结果当成一张临时表t select min(t.grade) as minGrade from (select t.deptno,t.dname,s.grade from (select e.deptno,d.dname,avg(e.sal) as avgsal from emp e join dept d on e.deptno = d.deptno group by e.deptno,d.dname)t join salgrade s on t.avgsal between s.losal and s.hisal)t; +----------+ | minGrade | +----------+ | 3 | +----------+ select t.deptno,t.dname,s.grade from (select e.deptno,d.dname,avg(e.sal) as avgsal from emp e join dept d on e.deptno = d.deptno group by e.deptno,d.dname)t join salgrade s on t.avgsal between s.losal and s.hisal where s.grade = (select min(t.grade) as minGrade from (select t.deptno,t.dname,s.grade from (select e.deptno,d.dname,avg(e.sal) as avgsal from emp e join dept d on e.deptno = d.deptno group by e.deptno,d.dname)t join salgrade s on t.avgsal between s.losal and s.hisal)t); +--------+-------+-------+ | deptno | dname | grade | +--------+-------+-------+ | 30 | SALES | 3 | +--------+-------+-------+
8.取得比普通员工(员工代码没有在mgr上出现的)的最高薪水还要高的经理人姓名 第一步:找出普通员工(员工代码没有出现在mgr上的) 1.1 先找出mgr有哪些人 select distinct mgr from emp; +------+ | mgr | +------+ | 7902 | | 7698 | | 7839 | | 7566 | | NULL | | 7788 | | 7782 | +------+ select * from emp where empno in(select distinct mgr from emp); +-------+-------+-----------+------+------------+---------+------+--------+ | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | +-------+-------+-----------+------+------------+---------+------+--------+ | 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 | | 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 | | 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | | 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | | 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 | | 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | +-------+-------+-----------+------+------------+---------+------+--------+ select max(sal) as maxsal from emp where empno not in(select distinct mgr from emp where mgr is not null); +---------+ | maxsal | +---------+ | 1600.00 | +---------+ not in不会自动忽略空值 in会自动忽略空值 select ename from emp where sal > (select max(sal) as maxsal from emp where empno not in(select distinct mgr from emp where mgr is not null)); +-------+ | ename | +-------+ | JONES | | BLAKE | | CLARK | | SCOTT | | KING | | FORD | +-------+
第一步:找出普通员工(员工代码没有出现在mgr上的) 1.1 先找出mgr有哪些人 select distinct mgr from emp; +------+ | mgr | +------+ | 7902 | | 7698 | | 7839 | | 7566 | | NULL | | 7788 | | 7782 | +------+ select * from emp where empno in(select distinct mgr from emp); +-------+-------+-----------+------+------------+---------+------+--------+ | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | +-------+-------+-----------+------+------------+---------+------+--------+ | 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 | | 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 | | 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | | 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | | 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 | | 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | +-------+-------+-----------+------+------------+---------+------+--------+ select max(sal) as maxsal from emp where empno not in(select distinct mgr from emp where mgr is not null); +---------+ | maxsal | +---------+ | 1600.00 | +---------+ not in不会自动忽略空值 in会自动忽略空值 select ename from emp where sal > (select max(sal) as maxsal from emp where empno not in(select distinct mgr from emp where mgr is not null)); +-------+ | ename | +-------+ | JONES | | BLAKE | | CLARK | | SCOTT | | KING | | FORD | +-------+
这里有一个很关键的地方,not in 没有排除null值,如果存在null值和not in 做计算,得带的值就是null
mysql> select * from emp where empno not in(select distinct mgr from emp); Empty set mysql>
select distinct mgr from emp 的结果存在null值
这里not in 没有去掉null值得到的结果就是空
9.取得薪水最高的前五名员工 select * from emp order by sal desc limit 0,5; +-------+-------+-----------+------+------------+---------+------+--------+ | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | +-------+-------+-----------+------+------------+---------+------+--------+ | 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 | | 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | | 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | | 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 | | 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 | +-------+-------+-----------+------+------------+---------+------+--------+ 10.取得薪水最高的第六到第十名员工 select * from emp order by sal desc limit 5,5; +-------+--------+----------+------+------------+---------+---------+--------+ | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | +-------+--------+----------+------+------------+---------+---------+--------+ | 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | | 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 | | 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | | 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 | | 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | +-------+--------+----------+------+------------+---------+---------+--------+ 11.取得最后入职的5名员工 select * from emp order by hiredate desc limit 5; +-------+--------+---------+------+------------+---------+------+--------+ | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | +-------+--------+---------+------+------------+---------+------+--------+ | 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 | | 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | | 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 | | 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | | 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 | +-------+--------+---------+------+------------+---------+------+--------+
12.取得每个薪水等级有多少员工 第一步:查询出每个员工的薪水等级 select e.ename,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal order by s.grade; +--------+-------+ | ename | grade | +--------+-------+ | JAMES | 1 | | SMITH | 1 | | ADAMS | 1 | | MILLER | 2 | | WARD | 2 | | MARTIN | 2 | | ALLEN | 3 | | TURNER | 3 | | BLAKE | 4 | | FORD | 4 | | CLARK | 4 | | SCOTT | 4 | | JONES | 4 | | KING | 5 | +--------+-------+ 将以上查询结果当成临时表t(ename,grade) select t.grade,count(t.ename) as totalEmp from (select e.ename,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal) t group by t.grade; +-------+----------+ | grade | totalEmp | +-------+----------+ | 1 | 3 | | 2 | 3 | | 3 | 2 | | 4 | 5 | | 5 | 1 | +-------+----------+
posted on 2018-01-30 15:01 luzhouxiaoshuai 阅读(1350) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!