题目链接:LeetCode183:从不订购的客户
解题思路
要找出所有从未下过订单的客户,核心思路是筛选出在 Customers
表中存在但在 Orders
表中无关联记录的客户。实现方式有两种高效方法:
-
LEFT JOIN
+IS NULL
- 将
Customers
表左连接Orders
表,连接条件为Customers.id = Orders.customerId
。 - 若某个客户无订单,则连接后
Orders.id
为NULL
。 - 直接通过
WHERE Orders.id IS NULL
过滤出目标客户。
- 将
-
NOT EXISTS
子查询- 对于
Customers
表中的每个客户,检查是否存在关联的订单记录。 - 若不存在关联订单,则选择该客户。
- 对于
效率对比:
LEFT JOIN
在大多数数据库(如 MySQL)中效率更高,因它只需单次遍历连接表并利用索引。NOT EXISTS
在逻辑上清晰,但可能因子查询导致额外扫描。- 推荐使用
LEFT JOIN
以最小化执行时间和内存消耗。
索引优化:
- 确保
Orders.customerId
有索引(外键通常自动索引)。 Customers.id
作为主键已有索引,可加速连接。
代码实现(MySQL版)
SELECT
c.name AS Customers -- 选择客户姓名,结果列名为 Customers
FROM
Customers c -- 主表:客户表
LEFT JOIN
Orders o -- 左连接订单表
ON c.id = o.customerId -- 连接条件:客户ID匹配
WHERE
o.id IS NULL; -- 过滤条件:无关联订单(订单ID为NULL)
代码说明
-
LEFT JOIN
:- 保留
Customers
表的所有记录,即使Orders
表中无匹配。 - 无订单的客户在连接后,
Orders
表的所有列均为NULL
。
- 保留
-
过滤条件:
WHERE o.id IS NULL
精确筛选出无订单的客户(因Orders.id
是主键,非空;若连接后为NULL
即表示无订单)。
-
列名处理:
- 结果列命名为
Customers
以符合题目要求。
- 结果列命名为
-
执行优化:
- 利用索引快速匹配连接条件(
Customers.id
和Orders.customerId
)。 - 避免全表扫描,仅需单次遍历即可完成过滤。
- 利用索引快速匹配连接条件(
性能关键:
- 索引确保连接操作高效(
O(N log M)
复杂度)。 LEFT JOIN
比NOT IN
或子查询更节省内存,避免创建临时结果集。