大数据学习(118)-SQL面试问题总结

发布于:2025-05-26 ⋅ 阅读:(27) ⋅ 点赞:(0)

🍋🍋大数据学习🍋🍋

🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。
💖如果觉得博主的文章还不错的话,请点赞👍+收藏⭐️+留言📝支持一下博主哦🤞


在 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 的值。
  • WHERE 是结果过滤条件:先完成连接(保留左表所有行),再过滤结果中不满足条件的行(包括左表行)。
    • 例 2 结果:仅保留右表金额 > 100 的用户(等价于 INNER JOIN),左表无订单或订单金额 ≤ 100 的用户会被过滤。

陷阱提醒:LEFT JOIN 中若条件涉及右表字段,写在 WHERE 会导致左表部分行被过滤,需根据需求选择。

2. 多表连接的逻辑顺序

问题:写出三表连接(A LEFT JOIN B ON ..., A INNER JOIN C ON ...)的执行顺序。
答案要点
SQL 执行顺序(简化版):

  1. FROM A:确定主表。
  2. LEFT JOIN B ON ...:将 B 与 A 连接,保留 A 所有行。
  3. 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 + 聚合函数)

需求:查询所有用户(包括无订单用户),统计其订单总数和总金额。
表结构

  • 用户表 usersuser_id(主键)、username
  • 订单表 ordersorder_iduser_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_idnameage
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 年,且商品类别为 “电子产品”。
表结构

  • usersuser_id
  • ordersorder_iduser_idorder_time
  • order_itemsorder_iditem_id
  • productsitem_idcategory
    错误写法
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 可能导致执行计划复杂,性能下降。
优化

  • 拆分为子查询或临时表;
  • 避免冗余关联(如重复连接同一表)。

网站公告

今日签到

点亮在社区的每一天
去签到