SQL LEFT JOIN 完整解题教程
📋 原题
题目: 编写解决方案,报告 Person表中每个人的姓、名、城市和州。如果 personId的地址不在 Address表中,则报告为null。以任意顺序返回结果表。
表结构
表: Person
列名 | 类型 |
---|---|
PersonId | int |
FirstName | varchar |
LastName | varchar |
personId 是该表的主键(具有唯一值的列)。该表包含一些人的 ID 和他们的姓和名的信息。
表: Address
列名 | 类型 |
---|---|
PersonId | int |
FirstName | varchar |
LastName | varchar |
addressId 是该表的主键(具有唯一值的列)。该表的每一行都包含一个 ID = PersonId 的人的城市和州的信息。
示例数据
输入:
Person表:
personId | lastName | firstName |
---|---|---|
1 | Wang | Allen |
2 | Alice | Bob |
Address表:
addressId | personId | city | state |
---|---|---|---|
1 | 2 | New York City | New York |
2 | 3 | Leetcode | California |
期望输出:
firstName | lastName | city | state |
---|---|---|---|
Allen | Wang | Null | Null |
Bob | Alice | New York City | New York |
📊 1. 数据分析
数据关系梳理
- Person表中的数据:
- personId=1: Allen Wang
- personId=2: Bob Alice
- Address表中的数据:
- personId=2: New York City, New York
- personId=3: Leetcode, California
关键发现
- Allen Wang (personId=1):在Person表中存在,但Address表中没有对应记录
- Bob Alice (personId=2):在Person表中存在,Address表中有对应记录
- personId=3:只在Address表中存在,Person表中没有此人
题目要求分析
- ✅ 必须显示Person表中的所有人
- ✅ 如果有地址信息,则显示具体地址
- ✅ 如果没有地址信息,则显示NULL
- ❌ 不需要显示只在Address表中存在的记录
💡 2. 解题思路
问题本质
这是一个典型的"主表完整显示 + 从表补充信息"的问题。
思路分析
- 确定主表:Person表(因为要显示"每个人"的信息)
- 确定从表:Address表(提供地址补充信息)
- 处理缺失数据:部分人可能没有地址信息
- 选择连接方式:需要保留主表的所有记录
JOIN类型选择
JOIN类型 | 效果 | 是否符合要求 |
---|---|---|
INNER JOIN | 只显示两表都有的记录 | ❌ 会丢失Allen Wang |
LEFT JOIN | 显示左表所有记录 | ✅ 完美符合 |
RIGHT JOIN | 显示右表所有记录 | ❌ 会包含personId=3 |
结论:使用LEFT JOIN
💻 3. 代码实现
SQL代码
SELECT
p.FirstName,
p.LastName,
a.City,
a.State
FROM Person p
LEFT JOIN Address a ON p.PersonId = a.PersonId;
代码解析
SELECT p.FirstName, – 选择Person表的名字 p.LastName, – 选择Person表的姓氏 a.City, – 选择Address表的城市(可能为NULL) a.State – 选择Address表的州(可能为NULL) FROM Person p – 主表:Person,别名p LEFT JOIN Address a – 左连接Address表,别名a ON p.PersonId = a.PersonId; – 连接条件:PersonId相等
执行过程模拟
- 扫描Person表:
- 找到 personId=1 (Allen Wang)
- 找到 personId=2 (Bob Alice)
- 对每个Person记录,在Address表中查找匹配:
- personId=1 → Address表中无匹配 → City和State为NULL
- personId=2 → Address表中有匹配 → City="New York City", State="New York"
- 组合结果:
- (Allen, Wang, NULL, NULL)
- (Bob, Alice, New York City, New York)
执行结果
firstName | lastName | city | state |
---|---|---|---|
Allen | Wang | NULL | NULL |
Bob | Alice | New York City | New York |
🤔 4. 思考
为什么不能用INNER JOIN?
错误方案:
SELECT p.FirstName, p.LastName, a.City, a.State FROM Person p INNER JOIN Address a ON p.PersonId = a.PersonId;
结果对比
方案 | Allen Wang是否显示 | 结果正确性 |
---|---|---|
LEFT JOIN | ✅ 显示,地址为NULL | ✅ 正确 |
INNER JOIN | ❌ 不显示 | ❌ 错误 |
如果需求改变怎么办?
场景1:显示所有地址信息(包括没有对应人员的地址)
SELECT p.FirstName, p.LastName, a.City, a.State FROM Address a LEFT JOIN Person p ON a.PersonId = p.PersonId;
场景2:只显示有地址的人员
SELECT p.FirstName, p.LastName, a.City, a.State FROM Person p INNER JOIN Address a ON p.PersonId = a.PersonId;
关键学习点
- LEFT JOIN的核心作用:保留左表的所有记录,右表没有匹配时用NULL填充
- 主表选择原则:题目要求显示"所有"记录的表作为主表(左表)
- NULL值处理:LEFT JOIN自动处理缺失数据,无需额外代码
- 表别名的重要性:避免字段名冲突,提高代码可读性
解题模板
遇到类似问题时,可以按以下步骤分析:
- 识别主表:题目要求完整显示的表
- 识别从表:提供补充信息的表
- 确定连接条件:通常是主键与外键的关系
- 选择JOIN类型:主表完整显示选LEFT JOIN
- 处理NULL值:LEFT JOIN自动处理,无需特殊代码
练习题
练习1: 有Employee表和Department表,查询所有员工的姓名和部门名称,没有部门的员工也要显示。
练习2: 有Student表和Score表,查询所有学生的姓名和数学成绩,没有数学成绩的学生也要显示。
练习3: 有Customer表和Order表,查询所有客户的姓名和最近一次订单日期,没有订单的客户也要显示。
总结
LEFT JOIN是处理"主表完整显示,从表补充信息"场景的最佳选择。掌握这个模式后,你就能轻松应对各种类似的数据库查询问题。
记住关键点:以需要完整显示的表作为LEFT JOIN的左表。
Comments