175. 组合两个表

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

关键发现

  1. Allen Wang (personId=1):在Person表中存在,但Address表中没有对应记录
  2. Bob Alice (personId=2):在Person表中存在,Address表中有对应记录
  3. personId=3:只在Address表中存在,Person表中没有此人

题目要求分析

  • ✅ 必须显示Person表中的所有人
  • ✅ 如果有地址信息,则显示具体地址
  • ✅ 如果没有地址信息,则显示NULL
  • ❌ 不需要显示只在Address表中存在的记录

💡 2. 解题思路

问题本质

这是一个典型的"主表完整显示 + 从表补充信息"的问题。

思路分析

  1. 确定主表:Person表(因为要显示"每个人"的信息)
  2. 确定从表:Address表(提供地址补充信息)
  3. 处理缺失数据:部分人可能没有地址信息
  4. 选择连接方式:需要保留主表的所有记录

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相等

执行过程模拟

  1. 扫描Person表
    • 找到 personId=1 (Allen Wang)
    • 找到 personId=2 (Bob Alice)
  2. 对每个Person记录,在Address表中查找匹配
    • personId=1 → Address表中无匹配 → City和State为NULL
    • personId=2 → Address表中有匹配 → City="New York City", State="New York"
  3. 组合结果
    • (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;

关键学习点

  1. LEFT JOIN的核心作用:保留左表的所有记录,右表没有匹配时用NULL填充
  2. 主表选择原则:题目要求显示"所有"记录的表作为主表(左表)
  3. NULL值处理:LEFT JOIN自动处理缺失数据,无需额外代码
  4. 表别名的重要性:避免字段名冲突,提高代码可读性

解题模板

遇到类似问题时,可以按以下步骤分析:

  1. 识别主表:题目要求完整显示的表
  2. 识别从表:提供补充信息的表
  3. 确定连接条件:通常是主键与外键的关系
  4. 选择JOIN类型:主表完整显示选LEFT JOIN
  5. 处理NULL值:LEFT JOIN自动处理,无需特殊代码

练习题

练习1: 有Employee表和Department表,查询所有员工的姓名和部门名称,没有部门的员工也要显示。

练习2: 有Student表和Score表,查询所有学生的姓名和数学成绩,没有数学成绩的学生也要显示。

练习3: 有Customer表和Order表,查询所有客户的姓名和最近一次订单日期,没有订单的客户也要显示。


总结

LEFT JOIN是处理"主表完整显示,从表补充信息"场景的最佳选择。掌握这个模式后,你就能轻松应对各种类似的数据库查询问题。

记住关键点:以需要完整显示的表作为LEFT JOIN的左表。