没卖给 RED 公司的销售员:先找出卖过的,再取反
LeetCode 607 · 反连接、多层子查询
面试怎么回答
先求出卖过给 RED 的销售员(订单 JOIN 公司,公司名为 RED),再用 NOT EXISTS 从全部销售员里排除。直接筛「公司不是 RED 的订单」是错的,因为会漏掉没下过单的人,也会留下同时卖给过 RED 的人。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
有销售员表、公司表、订单表(订单记录销售员和公司)。列出从没向名为 RED 的公司卖过东西的销售员姓名。
表结构
- salesperson:sales_id(主键)、name、salary、commission_rate、hire_date
- company:com_id(主键)、name、city
- orders:order_id(主键)、order_date、com_id、sales_id、amount
思路
正面找「没卖给 RED」不好找,反过来:先找出卖过给 RED 的销售员集合(订单关联公司,公司名为 RED),再从全部销售员里排除这个集合。排除可以用 NOT IN、NOT EXISTS 或 LEFT JOIN + IS NULL。
参考解法
select name
from salesperson
where sales_id not in
(
select sales_id
from orders
where com_id =
(
select com_id
from company
where name ='RED'
)
)
另一种写法:NOT EXISTS 写法
SELECT s.name
FROM salesperson s
WHERE NOT EXISTS (
SELECT 1 FROM orders o JOIN company c ON o.com_id = c.com_id
WHERE c.name = 'RED' AND o.sales_id = s.sales_id
)
易错点
- 写成「订单里公司不是 RED 的销售员」是错的:一个人可能既卖给过 RED 也卖给过别人,而且从没下过单的销售员也会被漏掉。
- NOT IN 的子查询里如果有 NULL 的 sales_id,结果会变成空集。