大数据学习(118)-SQL面试问题总结
🍋🍋大数据学习🍋🍋
🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。
💖如果觉得博主的文章还不错的话,请点赞👍+收藏⭐️+留言📝支持一下博主哦🤞
在 SQL 面试中,JOIN
是高频考点,面试官通常会考察对不同连接类型的理解、应用场景、性能优化以及关联条件的逻辑。
一、基础概念:JOIN 的类型与区别
1. 常见 JOIN 类型对比
连接类型 | 英文全称 | 核心逻辑 | 结果行数特点 |
---|---|---|---|
INNER JOIN | 内连接 | 仅返回两张表中满足关联条件的行(交集) | 可能少于或等于原表行数 |
LEFT JOIN | 左外连接 | 返回左表所有行,右表匹配行,无匹配时右表字段为 NULL | 至少等于左表行数 |
RIGHT JOIN | 右外连接 | 返回右表所有行,左表匹配行,无匹配时左表字段为 NULL | 至少等于右表行数 |
FULL JOIN | 全外连接(全连接) | 返回左表和右表所有行,无匹配时对应字段为 NULL (等价于 LEFT+RIGHT) | 可能多于两表行数之和(去重前) |
CROSS JOIN | 交叉连接(笛卡尔积) | 不使用关联条件,返回两表所有行的组合(左表行数 × 右表行数) | 结果集最大,需避免滥用 |
2. 面试必问:LEFT JOIN 和 INNER JOIN 的区别?
答案要点:
- 结果集差异:LEFT JOIN 包含左表全部行,无匹配时右表字段为
NULL
;INNER JOIN 仅返回匹配行。 - 应用场景:
- LEFT JOIN 用于统计左表数据的关联情况(如 “查询所有用户及其订单”);
- INNER JOIN 用于筛选两表均存在的数据(如 “查询同时有用户和订单的记录”)。
二、面试高频问题与陷阱
1. 关联条件(ON vs WHERE)
问题:LEFT JOIN 中,条件写在 ON
和 WHERE
有什么区别?
示例:
-- 场景:左表 A(用户表),右表 B(订单表),查询用户及其订单,且订单金额 > 100
-- 写法 1:条件在 ON 中
SELECT A.name, B.amount
FROM A
LEFT JOIN B ON A.id = B.user_id AND B.amount > 100; -- 写法 2:条件在 WHERE 中
SELECT A.name, B.amount
FROM A
LEFT JOIN B ON A.id = B.user_id
WHERE B.amount > 100;
- ON 是连接条件:在生成临时表时过滤右表数据,不满足条件的右表行仍会以
NULL
形式保留在结果中(左表行保留)。- 例 1 结果:所有用户都会出现,右表字段
amount
为NULL
或满足金额 > 100 的值。
- 例 1 结果:所有用户都会出现,右表字段
- WHERE 是结果过滤条件:先完成连接(保留左表所有行),再过滤结果中不满足条件的行(包括左表行)。
- 例 2 结果:仅保留右表金额 > 100 的用户(等价于 INNER JOIN),左表无订单或订单金额 ≤ 100 的用户会被过滤。
陷阱提醒:LEFT JOIN 中若条件涉及右表字段,写在 WHERE 会导致左表部分行被过滤,需根据需求选择。
2. 多表连接的逻辑顺序
问题:写出三表连接(A LEFT JOIN B ON ..., A INNER JOIN C ON ...)的执行顺序。
答案要点:
SQL 执行顺序(简化版):
- FROM A:确定主表。
- LEFT JOIN B ON ...:将 B 与 A 连接,保留 A 所有行。
- INNER JOIN C ON ...:将结果与 C 连接,仅保留 C 中匹配的行。
关键点:多表连接时,先处理 ON 条件,再按连接类型合并结果,最后处理 WHERE/HAVING 等后续条件。
3. 自连接(Self JOIN)的应用
问题:如何用自连接查询 “员工及其上级领导”?
SELECT e.emp_name AS 员工, m.emp_name AS 上级领导
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.emp_id;
要点:自连接需为表取别名(如 e
和 m
),区分主表和关联表。
三、经典面试例题
例题 1:统计用户订单情况(LEFT JOIN + 聚合函数)
需求:查询所有用户(包括无订单用户),统计其订单总数和总金额。
表结构:
- 用户表
users
:user_id
(主键)、username
- 订单表
orders
:order_id
、user_id
(外键)、amoun
SELECT u.user_id,u.username,COUNT(o.order_id) AS 订单总数,SUM(o.amount) AS 总金额
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
GROUP BY u.user_id, u.username;
关键点:
- 聚合函数(如
COUNT
)对NULL
行(无订单用户)会返回0
或NULL
?COUNT(o.order_id)
对NULL
行返回0
(因为order_id
为NULL
时不计入统计);- 若需强制返回
0
,可使用COALESCE(SUM(o.amount), 0)
。
例题 2:找出重复数据(INNER JOIN + 自连接)
需求:在 students
表中找出姓名和年龄都重复的学生。
表结构:student_id
、name
、age
SQL 示例:
SELECT s1.name, s1.age
FROM students s1
INNER JOIN students s2 ON s1.name = s2.name AND s1.age = s2.age AND s1.student_id > s2.student_id
GROUP BY s1.name, s1.age;
要点:
- 自连接通过
student_id > student_id
避免同一行匹配自身; - 结果可通过
DISTINCT
去重。
例题 3:多表连接关联条件优先级(陷阱题)
需求:查询用户及其订单和商品信息,要求订单时间在 2023 年,且商品类别为 “电子产品”。
表结构:
users
:user_id
orders
:order_id
、user_id
、order_time
order_items
:order_id
、item_id
products
:item_id
、category
错误写法:
SELECT u.user_id, o.order_id, p.item_id
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
LEFT JOIN order_items oi ON o.order_id = oi.order_id
LEFT JOIN products p ON oi.item_id = p.item_id
WHERE o.order_time >= '2023-01-01' AND p.category = '电子产品';
问题:WHERE
条件中的 o.order_time
和 p.category
会过滤掉左表(users
)的部分行,导致无订单或非电子产品的用户被排除,违背 LEFT JOIN
保留左表所有行的初衷。
正确写法:
SELECT u.user_id, o.order_id, p.item_id
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id AND o.order_time >= '2023-01-01'
LEFT JOIN order_items oi ON o.order_id = oi.order_id
LEFT JOIN products p ON oi.item_id = p.item_id AND p.category = '电子产品';
要点:将过滤条件移至 ON
中,确保左表(users
)所有行保留,右表不满足条件的字段为 NULL
。
四、性能优化:JOIN 的常见陷阱
1. 避免大表 CROSS JOIN
问题:CROSS JOIN 会生成笛卡尔积,导致结果集爆炸,严重影响性能。
优化:
- 必须使用时,确保关联条件(
ON
)能大幅过滤数据; - 优先用
INNER JOIN
或其他连接类型替代。
2. 索引优化
场景:JOIN 字段(如外键)未创建索引,导致全表扫描。
优化:
- 为连接条件中的字段(如
A.id = B.user_id
中的user_id
)创建索引; - 注意:LEFT JOIN 中,索引应优先创建在右表(被驱动表)的连接字段上。
3. 减少 JOIN 表数量
问题:超过 3 张表的 JOIN 可能导致执行计划复杂,性能下降。
优化:
- 拆分为子查询或临时表;
- 避免冗余关联(如重复连接同一表)。