LeetCode 175. 组合两个表
题目描述


题意分析
Person保存人员编号、姓和名,Address保存人员编号对应的城市和州。结果必须包含Person中的每个人;找不到地址的人也要保留,只把城市和州显示为NULL。因此要先确定哪些行不能丢:是人员记录,而不是地址记录。将
Person放在左侧做LEFT JOIN,恰好能保留这些行;普通内连接只返回匹配成功的人员,会漏掉没有地址的人。两表用
personId关联。Address.addressId标识地址记录本身,不能拿它与人员编号直接比较。输出只需要姓名、城市和州,无需分组或排序。
解法:以 Person 为主表做 LEFT JOIN
核心思路
[!blue]
对
Person AS p中的每个人,按照a.personId = p.personId查找地址。找到匹配行时,把姓名和对应的地址字段组合起来;一个匹配行也没有时,左连接仍输出该人员,并把右表字段补为NULL。这样每条人员记录至少出现一次,而只存在于
Address、在Person中找不到对应人员的记录不会被独立输出。若同一个人匹配多条地址,连接会按每条地址展开多行;题目没有要求任选一条,因此不应擅自聚合或去重。
ON中只写两张表的匹配关系。最终不再添加右表过滤条件,才能保留左连接补出的空值行。
解题步骤
- 从
Person AS p开始查询,确定必须保留的左表。- 用
LEFT JOIN Address AS a连接地址表。- 在
ON中要求两边personId相同。- 依次选择
firstName、lastName、city、state;未匹配时后两列会自然为NULL。样例中 Allen 没有地址,所以仍保留姓名并补两个
NULL;Bob 匹配到纽约地址;地址表中人员编号为 3 的记录没有对应人员,不会单独出现在结果中。
代码实现
SELECT
p.firstName,
p.lastName,
a.city,
a.state
FROM Person AS p
LEFT JOIN Address AS a
ON a.personId = p.personId;
复杂度分析
设两张表分别有 $P$、$A$ 行,结果有 $R$ 行。SQL 的实际开销取决于索引与执行计划,不能仅从语句确定唯一复杂度。
- 时间复杂度:以哈希左连接为例,扫描两表并输出结果约为 $O(P+A+R)$;朴素嵌套循环则可能达到 $O(PA+R)$。若右表连接列有索引,可以通过索引查找减少匹配工作。
- 空间复杂度:若为右表构建哈希表,额外空间为 $O(A)$,不计结果。使用其他连接算法时,临时空间也会相应变化。
关键点总结
[!green]
- “没有地址也要输出”直接决定使用保留人员表的外连接。
NULL由外连接补出,无需CASE或自行构造默认值。- 连接键表达表之间的人员关系,不能因为两列都是主键就拿来连接。
- 没有匹配与匹配多行是两种情况:前者补一行空值,后者保留每个匹配结果。
易错点总结
[!yellow]
- 使用
INNER JOIN:没有地址的人员会消失。- 把
Address放在保留侧:保留的是地址记录,不能保证所有人员出现。- 连接到
addressId:它是地址编号,不是地址所属人员的编号。- 在
WHERE中筛选右表城市:未匹配行中的城市是NULL,通常无法通过该筛选;本题不需要这种额外条件。- 添加
DISTINCT或按姓名分组:不同人员可能同名,连接结果也可能有多条地址,擅自合并会改变题意。- 使用
SELECT *:会带上题目没有要求的编号列,应明确选择四个输出字段。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 183. 从不订购的客户 | 简单 | 同样利用LEFT JOIN保留未匹配主表行,本题输出全部人员,原题只筛选未匹配者。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!