组合两个表 与 从不订购的客户
1. 组合两个表
题目描述
表: Person
+-------------+---------+ | 列名 | 类型 | +-------------+---------+ | PersonId | int | | FirstName | varchar | | LastName | varchar | +-------------+---------+ personId 是该表的主键(具有唯一值的列)。 该表包含一些人的 ID 和他们的姓和名的信息。
表: Address
+-------------+---------+ | 列名 | 类型 | +-------------+---------+ | AddressId | int | | PersonId | int | | City | varchar | | State | varchar | +-------------+---------+ addressId 是该表的主键(具有唯一值的列)。 该表的每一行都包含一个 ID = PersonId 的人的城市和州的信息。
编写解决方案,报告 Person
表中每个人的姓、名、城市和州。如果 personId
的地址不在 Address
表中,则报告为 null
。
以 任意顺序 返回结果表。
结果格式如下所示。
示例 1:
输入: 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 | +-----------+----------+---------------+----------+ 解释: 地址表中没有 personId = 1 的地址,所以它们的城市和州返回 null。 addressId = 1 包含了 personId = 2 的地址信息。
思路分析
SQL 中常见的表连接有 4 种,不同连接的逻辑完全不同,需根据需求选择:
连接类型 | 核心逻辑 | 是否符合本题需求 |
---|---|---|
LEFT JOIN(左连接) | 保留左表全部记录,右表无匹配则填充 NULL | ✅ 完全符合(需保留所有 Person) |
INNER JOIN(内连接) | 只保留两表都有匹配的记录 | ❌ 会过滤掉无地址的 Person(如示例中 PersonId=1 的 Allen) |
RIGHT JOIN(右连接) | 保留右表全部记录,左表无匹配则填充 NULL | ❌ 会保留 Address 表中无对应 Person 的记录(如示例中 PersonId=3 的地址),不符合 “展示 Person 表中人” 的需求 |
FULL JOIN(全连接) | 保留两表全部记录,无匹配则填充 NULL | ❌ 会额外保留 Address 表中无对应 Person 的记录,超出需求范围 |
代码实现
# Write your MySQL query statement below
SELECT p.FirstName, p.LastName, a.City, a.State
FROM Person p
LEFT JOIN Address a ON p.PersonId = a.PersonId;
2. 从不订购的客户
题目描述
Customers
表:
+-------------+---------+ | Column Name | Type | +-------------+---------+ | id | int | | name | varchar | +-------------+---------+ 在 SQL 中,id 是该表的主键。 该表的每一行都表示客户的 ID 和名称。
Orders
表:
+-------------+------+ | Column Name | Type | +-------------+------+ | id | int | | customerId | int | +-------------+------+ 在 SQL 中,id 是该表的主键。 customerId 是 Customers 表中 ID 的外键( Pandas 中的连接键)。 该表的每一行都表示订单的 ID 和订购该订单的客户的 ID。
找出所有从不点任何东西的顾客。
以 任意顺序 返回结果表。
结果格式如下所示。
示例 1:
输入: Customers table: +----+-------+ | id | name | +----+-------+ | 1 | Joe | | 2 | Henry | | 3 | Sam | | 4 | Max | +----+-------+ Orders table: +----+------------+ | id | customerId | +----+------------+ | 1 | 3 | | 2 | 1 | +----+------------+ 输出: +-----------+ | Customers | +-----------+ | Henry | | Max | +-----------+
思路分析
- 不能用 “
o.customerId = NULL
” 判断:SQL 中 NULL 代表 “未知值”,不能用普通的 “=”比较,必须用“
IS NULL”或“
IS NOT NULL`” 判断。 - 为什么不直接用 NOT IN?若用 “
SELECT name FROM Customers WHERE id NOT IN (SELECT customerId FROM Orders)
”,虽然看似可行,但存在隐患:若 Orders 表的 customerId 字段有 NULL 值,NOT IN 会返回空结果(SQL 语法特性),导致逻辑错误。而 LEFT JOIN + IS NULL 的方式更稳定,无此问题。
代码实现
# Write your MySQL query statement below
SELECT c.name AS Customers
FROM Customers c
LEFT JOIN Orders o ON c.id = o.customerId
WHERE o.customerId IS NULL;
总结
表连接的核心三要素
写连接查询时,必须明确以下三点,避免逻辑混乱:
- 左表与右表:谁需要被 “完整保留”,谁作为匹配表(如题目 1 中 Person 是左表,题目 2 中 Customers 是左表);
- 关联键:两表之间的 “桥梁”(如 PersonId、id 与 customerId),需确保关联键的类型一致(均为 int);
- 筛选条件:是保留所有匹配记录(题目 1),还是筛选无匹配记录(题目 2,用
IS NULL
)。