mysql学习之34道经典面试题

一、准备需要的表和数据

1.1 创建员工表以及插入数据

员工表建表语句

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');

1.2 创建部门表以及插入数据

部门表建表语句

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');

1.3 创建薪水等级表以及插入数据

薪水等级表建表语句

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');

表结构如下;



二 、34道经典面试题

2.1 取得每个部门最高薪水的人员名称

    a.查询每个部门最高薪水

SELECT
    e.deptno,
    max(e.sal) AS maxSal
FROM
    emp e
GROUP BY
    e.deptno;

b.将以上查询结果当成一个临时表 t(deptno,maxSal)---此语句不能运行属于分步逻辑语句

select  e.deptno,e.ename,t.maxSal ,e.sal from t join emp e on t.deptno=e.deptno where t.maxSal=e.sal;

c.把a中查询语句带入b中的t

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;

最终答案:

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;

运行结果


2.2 查询哪些人的薪水在部门平均水平之上

a.查询每个部门的平均薪水

#求出每个部门的平均薪水
SELECT
	e.deptno,
	max(e.sal)
FROM
	emp e
GROUP BY
	e.deptno;
b.将以上查询结果当成一个临时表 t(deptno,maxSal)
select t.deptno ,e.ename from  t join emp e on e.deptno=t.deptno where  e.sal >t.avgSal;

c.把a中j结果代入 临时表t

#将以上查询结果当成一个临时表 t(deptno,maxSal)把a中j结果代入 临时表t
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;

最终答案

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 order by e.deptno;
运行结果



2.3 取得部门中(所有人)平均薪水等级

此句话有两种含义

2.3.1)求出部门中(所有人)平均薪水的薪水等级

    a.求出部门的平均薪水

#求出部门的平均薪水
SELECT
	e.deptno,
	avg(e.sal) AS avgSal
FROM
	emp e
GROUP BY
	e.deptno;

    b.将以上查询结果当成一个临时表 t(deptno,avgSal)

select  t.deptno,t.avgSal,s.grade from  t join salgrade s on t.avgSal between s.losal and s.hisal order by 
t.deptno;

    c.把a中的结果代入b中临时表t

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
ORDER BY
	t.deptno;

最终答案

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
ORDER BY
	t.deptno;

运行结果:


2.3.2)求出部门中(所有人)平均的薪水等级

a)求出每个人的薪水等级

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;

b) 将a查询结果当成一个临时表 t(deptno,ename,grade)

SELECT
	t.deptno,
	avg(t.grade)
FROM
	(
		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
	) t
GROUP BY
	t.deptno;
最后结果:
SELECT
	t.deptno,
	avg(t.grade)
FROM
	(
		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
	) t
GROUP BY
	t.deptno;

运行结果:



2.4 不准用组函数(max),取得最高薪水(给出两种解决方案)

2.4.1 使用limit 结合order by 排序(降序),取第一个

SELECT
	sal
FROM
	emp
ORDER BY
	sal DESC
LIMIT 1;

最后答案:

SELECT
	sal
FROM
	emp
ORDER BY
	sal DESC
LIMIT 1;

运行结果:


2.4.2 采用自关联,通过自连接后a表的工资小于b表的薪水记录,并用distinc 去除重复,最后取不在范围内的结果

a.首先查出通过自连接后a表的工资小于b表的薪水记录,并用distinc 去除重复

#首先查出通过自连接后a表的工资小于b表的工资记录,并用distinc 去除重复
SELECT DISTINCT
	(a.sal)
FROM
	emp a
JOIN emp b ON a.sal < b.sal;


b.最后取不在a范围内的薪水结果

#查询出不在a结果薪水范围内的薪水
SELECT
	e.sal
FROM
	emp e
WHERE
	e.sal NOT IN (
		SELECT DISTINCT
			(a.sal)
		FROM
			emp a
		JOIN emp b ON a.sal < b.sal
	);

最后答案

#================================================
SELECT
	e.sal
FROM
	emp e
WHERE
	e.sal NOT IN (
		SELECT DISTINCT
			(a.sal)
		FROM
			emp a
		JOIN emp b ON a.sal < b.sal
	);

运行结果

2.5 取得平均薪水最高的部门的部门编号

a.查询各个部门的平均薪水

#==========================================================
SELECT
	e.deptno,
	avg(e.sal) AS avgSal
FROM
	emp e
GROUP BY
	e.deptno;


b.将a查询结果当做临时表 t(deptno,avgSal )查询各个部门平均薪水的最大值

select max(t.avgSal) as maxAvgSal from t;

代入a

#==========================================
SELECT
	max(t.avgSal) AS maxAvgSal
FROM
	(
		SELECT
			e.deptno,
			avg(e.sal) AS avgSal
		FROM
			emp e
		GROUP BY
			e.deptno
	) t;
c.通过分组过滤出最大平均薪水的部门编号
#====================================
SELECT
	e.deptno,
	avg(e.sal) 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
	);

最后答案

#====================================
SELECT
	e.deptno,
	avg(e.sal) 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
	);

运行结果

2.6 取得平均薪水最高的部门的部门名称

a.取得平均薪水最高的部门的部门编号即2.5题的答案

SELECT
	e.deptno,
	avg(e.sal) 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
	);

b.关联部门表一起查询

SELECT
	d.deptno,
	d.dname,
	avg(e.sal) avgSal
FROM
	emp e
JOIN dept d ON e.deptno = d.deptno
GROUP BY
	d.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
	);


最后答案

SELECT
	d.deptno,
	d.dname,
	avg(e.sal) avgSal
FROM
	emp e
JOIN dept d ON e.deptno = d.deptno
GROUP BY
	d.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
	);


运行结果

2.7 求平均薪水的等级最低的部门的部门名称

a,求各个部门平均薪水

SELECT
	d.deptno,
	d.dname,
	avg(sal) AS avgSal
FROM
	emp e
JOIN dept d ON e.deptno = d.deptno
GROUP BY
	d.deptno,
	d.dname;

+--------+------------+-------------+
| deptno | dname      | avgSal      |
+--------+------------+-------------+
|     10 | ACCOUNTING | 2916.666667 |
|     20 | RESEARCH   | 2175.000000 |
|     30 | SALES      | 1566.666667 |
+--------+------------+-------------+

b.将a结果当做一个临时表t(deptno,d,dnam,avgsal) 与等级表关联查询

SELECT
	s.grade,
	t.deptno,
	t.dname
FROM
	(
		SELECT
			d.deptno,
			d.dname,
			avg(sal) AS avgSal
		FROM
			emp e
		JOIN dept d ON e.deptno = d.deptno
		GROUP BY
			d.deptno,
			d.dname
	) t
JOIN salgrade s ON t.avgsal BETWEEN s.losal
AND s.hisal;

+-------+--------+------------+
| grade | deptno | dname      |
+-------+--------+------------+
|     4 |     10 | ACCOUNTING |
|     4 |     20 | RESEARCH   |
|     3 |     30 | SALES      |
+-------+--------+------------+

c,将b中结果当做一张临时表tem(grade,depeno,dname),查询最低等级

select min(tem.grade) as minGrade,tem.depeno,tem.dname from tem;

SELECT
	min(grade) AS minGrade
FROM
	(
		SELECT
			s.grade,
			t.deptno,
			t.dname
		FROM
			(
				SELECT
					d.deptno,
					d.dname,
					avg(sal) AS avgSal
				FROM
					emp e
				JOIN dept d ON e.deptno = d.deptno
				GROUP BY
					d.deptno,
					d.dname
			) t
		JOIN salgrade s ON t.avgsal BETWEEN s.losal
		AND s.hisal
	) tem;

+----------+
| minGrade |
+----------+
|        3 |
+----------+

d.把b的结果用c结果作为条件过滤

select s.grade,t.deptno,t.dname from (select d.deptno,d.dname,avg(sal) as avgSal  from emp e  join dept d on e.deptno =d.deptno group by d.deptno,d.dname)t join salgrade s on t.avgsal between s.losal and s.hisal where s.grade=3;

 

SELECT
	s.grade,
	t.deptno,
	t.dname
FROM
	(
		SELECT
			d.deptno,
			d.dname,
			avg(sal) AS avgSal
		FROM
			emp e
		JOIN dept d ON e.deptno = d.deptno
		GROUP BY
			d.deptno,
			d.dname
	) t
JOIN salgrade s ON t.avgsal BETWEEN s.losal
AND s.hisal
WHERE
	s.grade = (
		SELECT
			min(grade) AS minGrade
		FROM
			(
				SELECT
					s.grade,
					t.deptno,
					t.dname
				FROM
					(
						SELECT
							d.deptno,
							d.dname,
							avg(sal) AS avgSal
						FROM
							emp e
						JOIN dept d ON e.deptno = d.deptno
						GROUP BY
							d.deptno,
							d.dname
					) t
				JOIN salgrade s ON t.avgsal BETWEEN s.losal
				AND s.hisal
			) tem
	);
+-------+--------+-------+
| grade | deptno | dname |
+-------+--------+-------+
|     3 |     30 | SALES |

+-------+--------+-------+

最后答案

SELECT
	s.grade,
	t.deptno,
	t.dname
FROM
	(
		SELECT
			d.deptno,
			d.dname,
			avg(sal) AS avgSal
		FROM
			emp e
		JOIN dept d ON e.deptno = d.deptno
		GROUP BY
			d.deptno,
			d.dname
	) t
JOIN salgrade s ON t.avgsal BETWEEN s.losal
AND s.hisal
WHERE
	s.grade = (
		SELECT
			min(grade) AS minGrade
		FROM
			(
				SELECT
					s.grade,
					t.deptno,
					t.dname
				FROM
					(
						SELECT
							d.deptno,
							d.dname,
							avg(sal) AS avgSal
						FROM
							emp e
						JOIN dept d ON e.deptno = d.deptno
						GROUP BY
							d.deptno,
							d.dname
					) t
				JOIN salgrade s ON t.avgsal BETWEEN s.losal
				AND s.hisal
			) tem
	);


运行结果



2.8 取得比普通员工(员工代码没有出现在mgr上出现的)的最高薪水还要高的经理人姓名

a 查询出普通员工(员工代码没有出现在mgr上出现的)

       :a1) 查询出mgr 有哪些人

select e.mgr from emp e;

                        | mgr  |
                        +------+
                        | 7902 |
                        | 7698 |
                        | 7698 |
                        | 7839 |
                        | 7698 |
                        | 7839 |
                        | 7839 |
                        | 7566 |
                        | NULL |
                        | 7698 |
                        | 7788 |
                        | 7698 |
                        | 7566 |
                        | 7782 |
                        +------+
                        | 7782 |
                        +------+

mgr 有重复,所以要去除重复。          

 select distinct e.mgr from emp e;
                        +------+
                        | mgr  |
                        +------+
                        | 7902 |
                        | 7698 |
                        | 7839 |
                        | 7566 |
                        | NULL |
                        | 7788 |
                        | 7782 |
                        +------+

mgr 有空值,所以要去除空值。

SELECT DISTINCT
    e.mgr
FROM
    emp e
WHERE
    e.mgr IS NOT NULL;
                    +------+
                    | mgr  |
                    +------+
                    | 7902 |
                    | 7698 |
                    | 7839 |
                    | 7566 |
                    | 7788 |
                    | 7782 |
                    +------+

a2)查询不是mgr的普通员工所有信息
          

SELECT
	*
FROM
	emp e
WHERE
	e.empno NOT IN (
		SELECT DISTINCT
			e.mgr
		FROM
			emp e
		WHERE
			e.mgr IS NOT NULL
	);

+-------+--------+----------+------+------------+---------+---------+--------+
| EMPNO | ENAME  | JOB      | MGR  | HIREDATE   | SAL     | COMM    | DEPTNO |
+-------+--------+----------+------+------------+---------+---------+--------+
|  7369 | SMITH  | CLERK    | 7902 | 1980-12-17 |  800.00 |    NULL |     20 |
|  7499 | ALLEN  | SALESMAN | 7698 | 1981-02-20 | 1600.00 |  300.00 |     30 |
|  7521 | WARD   | SALESMAN | 7698 | 1981-02-22 | 1250.00 |  500.00 |     30 |
|  7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 |     30 |
|  7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 |    0.00 |     30 |
|  7876 | ADAMS  | CLERK    | 7788 | 1981-05-23 | 1100.00 |    NULL |     20 |
|  7900 | JAMES  | CLERK    | 7698 | 1981-12-03 |  950.00 |    NULL |     30 |
|  7934 | MILLER | CLERK    | 7782 | 1982-01-23 | 1300.00 |    NULL |     10 |
+-------+--------+----------+------+------------+---------+---------+--------+


b.查询出普通员工的最高薪水

SELECT
	max(e.sal)
FROM
	emp e
WHERE
	e.empno NOT IN (
		SELECT DISTINCT
			e.mgr
		FROM
			emp e
		WHERE
			e.mgr IS NOT NULL
	);

+----------+
| max(sal) |
+----------+
|  1600.00 |
+----------+

c 查询比普通员工工资还要高的员工---即经理

SELECT
	e.ename,e.sal
FROM
	emp e
WHERE
	e.sal > (
		SELECT
			max(sal)
		FROM
			emp e
		WHERE
			e.empno NOT IN (
				SELECT DISTINCT
					e.mgr
				FROM
					emp e
				WHERE
					e.mgr IS NOT NULL
			)
	)
                    +-------+---------+
                    | ename | sal     |
                    +-------+---------+
                    | JONES | 2975.00 |
                    | BLAKE | 2850.00 |
                    | CLARK | 2450.00 |
                    | SCOTT | 3000.00 |
                    | KING  | 5000.00 |
                    | FORD  | 3000.00 |

                    +-------+---------+

最后答案

SELECT
	e.ename,e.sal
FROM
	emp e
WHERE
	e.sal > (
		SELECT
			max(sal)
		FROM
			emp e
		WHERE
			e.empno NOT IN (
				SELECT DISTINCT
					e.mgr
				FROM
					emp e
				WHERE
					e.mgr IS NOT NULL
			)
	);

运行结果

2.9 取得薪水最高的前五名员工

最终答案

SELECT
    *
FROM
    emp e
ORDER BY
    sal DESC
LIMIT 0,
 5;

运行结果



2.10 取得薪水最高第六到第十名员工

最终答案:

SELECT
	*
FROM
	emp e
ORDER BY
	sal desc
LIMIT 5,
 5;
limit 一个参数表示从第几开始,第二个参数表示去的长度

运行结果

2.11 取得最后入职的五名员工

最终答案:

#---第一种写法
SELECT
	*
FROM
	emp e
ORDER BY
	HIREDATE desc
LIMIT 0,
 5;
#---第二种写法
SELECT
	*
FROM
	emp e
ORDER BY
	HIREDATE desc
LIMIT
 5;

运行结果:

2.12取得每个薪水等级有多少员工

最终答案

SELECT
	s.GRADE,
	COUNT(e.ename)
FROM
	emp e
JOIN salgrade s ON e.sal BETWEEN s.LOSAL
AND s.HISAL
GROUP BY
	s.GRADE;

运行结果








  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值