JOIN

SQL 笔试与手撕题教程

五种 JOIN

类型说明
INNER JOIN只保留两边都匹配的行
LEFT JOIN保留左表全部行,右表没匹配到的补 NULL
RIGHT JOIN保留右表全部行,左表没匹配到的补 NULL
FULL OUTER JOIN两边都保留,没匹配到的补 NULL
CROSS JOIN笛卡尔积,左表每行和右表每行两两组合

MySQL 不支持 FULL OUTER JOIN,可以用 LEFT JOIN UNION RIGHT JOIN 模拟。SQLite 也不支持 RIGHT JOINFULL OUTER JOIN

LEFT JOIN 经典套路

面试里 LEFT JOIN 考得最多,经典用法是"找出没有 XXX 的记录"

-- 找出从未下过单的用户
SELECT u.user_id, u.name
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.user_id IS NULL;

原理:LEFT JOIN 保留左表所有行,没有匹配的订单时 o.user_id 为 NULL。WHERE o.user_id IS NULL 筛出这些"没匹配到"的行。

等价写法:

-- NOT EXISTS
SELECT user_id, name FROM users u
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.user_id);

-- NOT IN(注意:如果子查询有 NULL 值,NOT IN 的行为可能不符合预期)
SELECT user_id, name FROM users
WHERE user_id NOT IN (SELECT user_id FROM orders);

多表 JOIN

实际业务中经常需要 JOIN 三四张表。写的时候注意:

练习

练习

没有成绩的学生

给定 studentsscores 两张表,找出没有任何成绩记录的学生姓名。
SQL 编辑器

点击「运行」查看查询结果

查看答案
参考答案
SELECT s.name
FROM students s
LEFT JOIN scores sc ON s.id = sc.student_id
WHERE sc.student_id IS NULL;
解析

LEFT JOIN 保留所有学生,没有成绩记录的学生在 scores 侧全为 NULL。Dave 没有任何成绩,会被筛出来。

练习

没有员工的部门

给定 departmentsemployees 两张表,找出没有任何员工的部门名称。
SQL 编辑器

点击「运行」查看查询结果

查看答案
参考答案
SELECT d.dept_name
FROM departments d
LEFT JOIN employees e ON d.dept_id = e.dept_id
WHERE e.emp_id IS NULL;
解析

同样的 LEFT JOIN + IS NULL 模式。Finance 部门没有员工,会被筛出来。