订阅更新

没卖给 RED 公司的销售员:先找出卖过的,再取反

SQL 实战 123 题 · 第 35 题 简单 约 2 分钟读完

LeetCode 607 · 反连接、多层子查询

本文目录
  1. 面试怎么回答
  2. 题意
  3. 表结构
  4. 思路
  5. 参考解法
  6. 易错点

面试怎么回答

先求出卖过给 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,结果会变成空集。
刷题进度保存在当前浏览器