Skip to content

Commit a25e529

Browse files
committed
更新了部分面试题
1 parent 583f15a commit a25e529

7 files changed

+957
-0
lines changed
File renamed without changes.

数据分析师SQL面试宝典-1.md

+317
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
## 数据分析师SQL面试宝典
2+
3+
### 题目1
4+
5+
MySQL 数据库中有如下所示的两张表部门表和员工表,请完成下面的查询。
6+
7+
部门表(`tb_dept`):三个字段分别代表部门编号(`dno`)、部门名称(`dname`)和部门所在地(`dloc`)。
8+
9+
| dno | dname | dloc |
10+
| :--: | :----: | :--: |
11+
| 10 | 会计部 | 北京 |
12+
| 20 | 研发部 | 成都 |
13+
| 30 | 销售部 | 重庆 |
14+
| 40 | 运维部 | 深圳 |
15+
16+
员工表(`tb_emp`):六个字段分别代表员工编号(`eno`)、姓名(`ename`)、职位(`job`)、主管编号(`mgr`)、月薪(`sal`)、所在部门编号(`dno`),其中主管编号参照了员工表的员工编号,所在部门编号参照了部门表的部门编号。
17+
18+
| eno | ename | job | mgr | sal | dno |
19+
| :--: | :----: | :------: | :--: | :--: | :--: |
20+
| 1359 | 胡一刀 | 销售员 | 3344 | 1800 | 30 |
21+
| 2056 | 乔峰 | 分析师 | 7800 | 5000 | 20 |
22+
| 3088 | 李莫愁 | 设计师 | 2056 | 3500 | 20 |
23+
| 3211 | 张无忌 | 程序员 | 2056 | 3200 | 20 |
24+
| 3233 | 丘处机 | 程序员 | 2056 | 3400 | 20 |
25+
| 3244 | 欧阳锋 | 程序员 | 3088 | 3200 | 20 |
26+
| 3251 | 张翠山 | 程序员 | 2056 | 4000 | 20 |
27+
| 3344 | 黄蓉 | 销售主管 | 7800 | 3000 | 30 |
28+
| 3577 | 杨过 | 会计 | 5566 | 2200 | 10 |
29+
| 3588 | 朱九真 | 会计 | 5566 | 2500 | 10 |
30+
| 4466 | 苗人凤 | 销售员 | 3344 | 2500 | 30 |
31+
| 5234 | 郭靖 | 出纳 | 5566 | 2000 | 10 |
32+
| 5566 | 宋远桥 | 会计师 | 7800 | 4000 | 10 |
33+
| 7800 | 张三丰 | 总裁 | NULL | 9000 | 20 |
34+
35+
#### 1. 查询员工和他的主管的姓名
36+
37+
参考答案:
38+
39+
```sql
40+
SELECT t1.ename AS 员工姓名
41+
, t2.ename AS 主管姓名
42+
FROM tb_emp AS t1
43+
LEFT JOIN tb_emp AS t2
44+
ON t1.mgr = t2.eno;
45+
```
46+
47+
> **说明**:本题通过自连接就可以完成,使用左外连接是为了将没有主管的总裁张三丰也能查出来。
48+
49+
#### 2. 查询月薪最高的员工姓名和月薪
50+
51+
参考答案:
52+
53+
方法一:嵌套查询(先查出最高的月薪再用它当条件筛选出对应的员工)
54+
55+
```sql
56+
SELECT ename
57+
, sal
58+
FROM tb_emp
59+
WHERE sal = (SELECT MAX(sal)
60+
FROM tb_emp);
61+
```
62+
63+
方法二:ALL运算符(拿你的月薪和所有人比较,看看是否满足条件`>=`
64+
65+
```sql
66+
SELECT ename
67+
, sal
68+
FROM tb_emp
69+
WHERE sal >= ALL(SELECT sal
70+
FROM tb_emp);
71+
```
72+
73+
方法三:计数法(月薪比你更高的员工人数为`0`,你就是月薪最高的)
74+
75+
```sql
76+
SELECT ename
77+
, sal
78+
FROM tb_emp AS t1
79+
WHERE (SELECT COUNT(*)
80+
FROM tb_emp AS t2
81+
WHERE t2.sal > t1.sal) = 0;
82+
```
83+
84+
方法四:存在性判断(不存在有人比你月薪更高,那你就是月薪最高的)
85+
86+
```sql
87+
SELECT ename
88+
, sal
89+
FROM tb_emp AS t1
90+
WHERE NOT EXISTS (SELECT 'x'
91+
FROM tb_emp AS t2
92+
WHERE t2.sal > t1.sal);
93+
```
94+
95+
> **说明**:存在性判断并不需要投影某个具体的字段,所以通常直接写常量`'x'``1`来代替具体的字段。
96+
97+
#### 3. 查询月薪Top3的员工姓名和月薪
98+
99+
参考答案:
100+
101+
```sql
102+
SELECT ename
103+
, sal
104+
FROM tb_emp AS t1
105+
WHERE (SELECT COUNT(*)
106+
FROM tb_emp AS t2
107+
WHERE t2.sal > t1.sal) < 3
108+
ORDER BY sal DESC;
109+
```
110+
111+
> **说明**:这个查询跟上一个查询的方法三道理是一样的,如果月薪比我更高的人不会有3个,那么我们就是Top3。
112+
113+
#### 4. 查询部门人数超过5个人的部门的编号和人数
114+
115+
参考答案:
116+
117+
```sql
118+
SELECT dno AS 部门编号
119+
, COUNT(*) AS 人数
120+
FROM tb_emp
121+
GROUP BY dno
122+
HAVING COUNT(*) > 5;
123+
```
124+
125+
> **说明**:分组之前的数据筛选使用`WHERE`子句,分组之后的数据筛选要使用`HAVING`子句。
126+
127+
#### 5. 查询所有部门的名称和人数
128+
129+
参考答案:
130+
131+
```sql
132+
SELECT dname AS 部门名称
133+
, COALESCE(total, 0) AS 部门人数
134+
FROM tb_dept AS t1
135+
LEFT JOIN (SELECT dno
136+
, COUNT(*) AS total
137+
FROM tb_emp
138+
GROUP BY dno) AS t2
139+
ON t1.dno = t2.dno;
140+
```
141+
142+
> **说明**:先通过一个嵌套查询获取到部门编号和人数,再通过左外连接的方式连接部门表。
143+
144+
#### 4. 查询月薪超过其所在部门平均月薪的员工的姓名、部门编号和月薪
145+
146+
参考答案:
147+
148+
```sql
149+
SELECT ename
150+
, dno
151+
, sal
152+
FROM tb_emp AS t1
153+
NATURAL JOIN (SELECT dno
154+
, AVG(sal) AS avg_sal
155+
FROM tb_emp
156+
GROUP BY dno) AS t2
157+
WHERE sal > avg_sal;
158+
```
159+
160+
#### 5. 查询部门中月薪最高的人姓名、月薪和所在部门名称
161+
162+
参考答案:
163+
164+
```sql
165+
SELECT ename
166+
, sal
167+
, dname
168+
FROM tb_dept AS t1
169+
NATURAL JOIN tb_emp AS t2
170+
WHERE (dno, sal) IN (SELECT dno
171+
, max(sal)
172+
FROM tb_emp
173+
GROUP BY dno);
174+
```
175+
176+
#### 6. 查询主管和普通员工的平均月薪
177+
178+
参考答案:
179+
180+
```sql
181+
SELECT tag AS 职级
182+
, ROUND(avg(sal), 2) AS 平均月薪
183+
FROM (SELECT sal
184+
, CASE WHEN EXISTS (SELECT 'x'
185+
FROM tb_emp AS t2
186+
WHERE t1.eno = t2.mgr)
187+
THEN '主管'
188+
ELSE '普通员工'
189+
END AS tag
190+
FROM tb_emp AS t1) AS tmp
191+
GROUP BY tag;
192+
```
193+
194+
> **说明**:先通过一个嵌套查询,给原来员工表的数据加上“主管”或“普通员工”的标签,然后根据标签分组数据再做聚合。
195+
196+
#### 7. 查询月薪排名4~6名的员工排名、姓名和月薪
197+
198+
参考答案:
199+
200+
方法一:不使用窗口函数
201+
202+
```sql
203+
SELECT *
204+
FROM (SELECT @a := @a + 1 AS 排名
205+
, ename AS 姓名
206+
, sal AS 月薪
207+
FROM tb_emp, (SELECT @a := 0) AS tmp
208+
ORDER BY sal DESC) AS tmp
209+
WHERE 排名 BETWEEN 4 AND 6;
210+
```
211+
212+
方法二:使用窗口函数
213+
214+
```sql
215+
SELECT *
216+
FROM (SELECT ename AS 姓名
217+
, sal AS 月薪
218+
, RANK() OVER (ORDER BY sal DESC) AS 排名
219+
FROM tb_emp) AS tmp
220+
WHERE 排名 between 4 and 6;
221+
```
222+
223+
> **说明**:上面方法一和方法二的查询结果并不相同,方法二的查询结果更符合我们对这个问题的认知,如果要获得跟方法一一样的结果,可以将窗口函数`RANK`修改为`ROW_NUMBER`即可。`RANK``DENSE_RANK``ROW_NUMBER`三个函数的差别大家可以自行了解。
224+
225+
#### 8. 查询每个部门月薪排前2名的员工姓名、月薪和部门编号
226+
227+
参考答案:
228+
229+
方法一:不使用窗口函数
230+
231+
```sql
232+
SELECT ename
233+
, sal
234+
, t1.dno
235+
FROM tb_emp AS t1
236+
WHERE (SELECT COUNT(*)
237+
FROM tb_emp AS t2
238+
WHERE t2.dno = t1.dno
239+
AND t2.sal > t1.sal) < 2
240+
ORDER BY dno ASC, sal DESC;
241+
```
242+
243+
方法二:使用窗口函数
244+
245+
```sql
246+
SELECT ename
247+
, sal
248+
, dno
249+
FROM (SELECT ename
250+
, sal
251+
, dno
252+
, RANK() OVER (PARTITION BY dno ORDER BY sal DESC) AS rn
253+
FROM tb_emp) AS tmp
254+
WHERE rn <= 2;
255+
```
256+
257+
> **说明**:上面的题目总体难度不大,但是覆盖到的 SQL 知识点还是比较多的,大家可以用这些题来热热身,再去挑战后面的 SQL 面试题,这些面试题主要是针对数据分析师的 SQL 面试题。如果对 SQL 的知识不太熟悉,大家可以先移步到我在B站上发布的视频[《数据分析师的SQL入门课》](https://www.bilibili.com/video/BV13V4y1H7mT)进行学习。下面是为大家编写好的建库建表和插入数据的SQL语句,有需要的可以用它来完成建库建表操作。
258+
>
259+
> ```SQL
260+
> -- 创建数据库
261+
> CREATE DATABASE `Q1` DEFAULT CHARSET utf8mb4;
262+
>
263+
> -- 切换数据库
264+
> USE `Q1`;
265+
>
266+
> -- 创建部门表
267+
> CREATE TABLE `tb_dept`
268+
> (
269+
> `dno` int NOT NULL COMMENT '编号',
270+
> `dname` varchar(10) NOT NULL COMMENT '名称',
271+
> `dloc` varchar(20) NOT NULL COMMENT '所在地',
272+
> PRIMARY KEY (`dno`)
273+
> );
274+
>
275+
> -- 插入部门数据
276+
> INSERT INTO `tb_dept`
277+
> VALUES
278+
> (10, '会计部', '北京'),
279+
> (20, '研发部', '成都'),
280+
> (30, '销售部', '重庆'),
281+
> (40, '运维部', '深圳');
282+
>
283+
> -- 创建员工表
284+
> CREATE TABLE `tb_emp`
285+
> (
286+
> `eno` int NOT NULL COMMENT '员工编号',
287+
> `ename` varchar(20) NOT NULL COMMENT '员工姓名',
288+
> `job` varchar(20) NOT NULL COMMENT '员工职位',
289+
> `mgr` int COMMENT '主管编号',
290+
> `sal` int NOT NULL COMMENT '员工月薪',
291+
> `dno` int NOT NULL COMMENT '所在部门编号',
292+
> PRIMARY KEY (`eno`),
293+
> CONSTRAINT `fk_emp_mgr` FOREIGN KEY (`mgr`) REFERENCES tb_emp (`eno`),
294+
> CONSTRAINT `fk_emp_dno` FOREIGN KEY (`dno`) REFERENCES tb_dept (`dno`)
295+
> );
296+
>
297+
> -- 插入员工数据
298+
> INSERT INTO `tb_emp`
299+
> VALUES
300+
> (7800, '张三丰', '总裁', NULL, 9000, 20),
301+
> (2056, '乔峰', '分析师', 7800, 5000, 20),
302+
> (3088, '李莫愁', '设计师', 2056, 3500, 20),
303+
> (3211, '张无忌', '程序员', 2056, 3200, 20),
304+
> (3233, '丘处机', '程序员', 2056, 3400, 20),
305+
> (3251, '张翠山', '程序员', 2056, 4000, 20),
306+
> (5566, '宋远桥', '会计师', 7800, 4000, 10),
307+
> (5234, '郭靖', '出纳', 5566, 2000, 10),
308+
> (3344, '黄蓉', '销售主管', 7800, 3000, 30),
309+
> (1359, '胡一刀', '销售员', 3344, 1800, 30),
310+
> (4466, '苗人凤', '销售员', 3344, 2500, 30),
311+
> (3244, '欧阳锋', '程序员', 3088, 3200, 20),
312+
> (3577, '杨过', '会计', 5566, 2200, 10),
313+
> (3588, '朱九真', '会计', 5566, 2500, 10);
314+
> ```
315+
316+
317+

0 commit comments

Comments
 (0)