LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

SQL教程-还在用NOT IN做数据对比?EXCEPT一行就搞定

admin
2026年5月27日 18:25 本文热度 72

运营说"帮我找出买了 A 类商品但没买 B 类的用户",你第一反应是什么?LEFT JOIN + IS NULL?NOT EXISTS?其实 SQL 早就给了你一行解法。

你可能从未用过它们

大多数分析师写了三年 SQL,都没碰过 EXCEPT 和 INTERSECT。

不是它们没用——而是很多人根本不知道有这两个关键字。

日常工作中,"找差异"和"找交集"的需求非常高频:

  • 上个月买过、这个月没买的流失用户
  • 同时参加过两次活动的重叠人群
  • A 系统有但 B 系统没有的数据差异

传统写法?LEFT JOIN + IS NULL,或者 NOT EXISTS 嵌套子查询。能跑,但可读性很差

花 5 分钟,把这两个运算函数彻底拿下。


先用一句话讲清楚

INTERSECT = 两边都有的(交集)

EXCEPT = 左边有、右边没有的(差集)

记住这张图:

INTERSECT:   🟦 ∩ 🟩  →  重叠的部分
EXCEPT:      🟦 - 🟩  →  🟦 独有的部分

INTERSECT:找出"两边都有的人"

基础语法

SELECT user_id FROM orders_202604
INTERSECT
SELECT user_id FROM orders_202605;

结果:同时在 4 月和 5 月都下过单的用户

一个真实的业务场景

运营想办一场"老用户回馈"活动,条件是——

"3 月份买过,而且 5 月份也买过的用户"

SELECT user_id
FROM orders
WHERE order_date BETWEEN'2026-03-01'AND'2026-03-31'
AND status ='已完成'

INTERSECT

SELECT user_id
FROM orders
WHERE order_date BETWEEN'2026-05-01'AND'2026-05-31'
AND status ='已完成';

干净、直白、没有 JOIN 的纠缠。

任何人看一眼就知道这段 SQL 在干什么。

和传统写法的对比

同样的需求,用 JOIN 写:

SELECT a.user_id
FROM (
    SELECTDISTINCT user_id FROM orders
    WHERE order_date BETWEEN'2026-03-01'AND'2026-03-31'
      AND status ='已完成'
) a
JOIN (
    SELECTDISTINCT user_id FROM orders
    WHERE order_date BETWEEN'2026-05-01'AND'2026-05-31'
      AND status ='已完成'
) b ON a.user_id = b.user_id;

功能一样,但多了三层嵌套、一个 JOIN、一个别名。

哪个更好维护,一目了然。


EXCEPT:找出"有 A 没有 B 的人"

基础语法

SELECT user_id FROM orders_202604
EXCEPT
SELECT user_id FROM orders_202605;

结果:4 月买过但 5 月没买过的用户——这就是你的流失预警名单

核心应用:用户流失分析

"帮我拉一下上个月有消费、这个月没有的用户。"

一句话需求,EXCEPT 一行搞定:

SELECT user_id
FROM orders
WHERE order_date BETWEEN'2026-04-01'AND'2026-04-30'
AND status ='已完成'

EXCEPT

SELECT user_id
FROM orders
WHERE order_date BETWEEN'2026-05-01'AND'2026-05-31';

用 NOT IN 能做到吗?

能,但有一个致命陷阱

-- 看似等价,其实有坑
SELECT user_id
FROM orders
WHERE order_date BETWEEN'2026-04-01'AND'2026-04-30'
AND status ='已完成'
AND user_id NOTIN (
      SELECT user_id FROM orders
      WHERE order_date BETWEEN'2026-05-01'AND'2026-05-31'
  );

如果子查询的结果里包含 NULL,NOT IN 会返回空结果。 整个查询白跑。

而 EXCEPT 自动处理 NULL,天然安全。

这是一个很多人踩过的坑,值得单独强调。


三个实战场景

场景一:A/B 测试人群隔离检查

上线 A/B 测试前,运营问:"实验组和对照组有没有重叠用户?"

SELECT user_id FROM ab_test_group WHERE group_name = '实验组'
INTERSECT
SELECT user_id FROM ab_test_group WHERE group_name = '对照组';

如果有结果返回——赶紧找人修数据,实验结论不可信。

场景二:多渠道用户去重

市场部投了抖音和微信两个渠道,需要看各渠道的独占用户

-- 只在抖音注册、没有在微信注册的用户
SELECT user_id FROM channel_users WHERE channel = '抖音'
EXCEPT
SELECT user_id FROM channel_users WHERE channel = '微信';

反过来换一下条件,就能拿到微信独占用户。两个渠道的增量价值一目了然。

场景三:数据一致性校对

财务系统和订单系统的数据对不上?快速找差异:

SELECT order_id FROM finance_orders
EXCEPT
SELECT order_id FROM biz_orders;

有结果就说明存在单边账——财务有记录但业务没有,或者反过来。排查范围瞬间缩小。


四条铁律,避免翻车

铁律一:列数和顺序必须一致

-- 正确 ✅ 两边都是 1 列
SELECT user_id FROM table_a
EXCEPT
SELECT user_id FROM table_b;

-- 报错 ❌ 左边 2 列,右边 1 列
SELECT user_id, order_id FROM table_a
EXCEPT
SELECT user_id FROM table_b;

EXCEPT 和 INTERSECT 不像 JOIN 靠列名匹配。 它们是按位置一一比较的,列数不同直接报错。

铁律二:默认去重

-- 如果左边有 3 条 user_id = 'U001',右边也有 2 条
-- EXCEPT 结果中 'U001' 只出现 1 次
SELECT user_id FROM orders_202604
EXCEPT
SELECT user_id FROM orders_202605;

大多数场景下这是你想要的行为。如果确实需要保留重复行,看下一条。

铁律三:不去重用 ALL

-- EXCEPT ALL:保留重复
SELECT user_id FROM orders_202604
EXCEPT ALL
SELECT user_id FROM orders_202605;

带 ALL 时,逻辑变成**"左边比右边多出来的部分"**。比如左边 3 个 U001,右边 2 个,结果会保留 1 个。

实际工作中 90% 的情况用不带 ALL 的版本就够了。知道有这个选项即可。

数据库兼容性

运算
MySQL
Oracle
SQL server
PostgreSQL
EXCEPT
✅ 8.0+
MINUS代替 
INTERSECT
✅ 8.0+


一张速查表,收藏备用

┌──────────────────────────────────────────────────┐
│  INTERSECT     两边都有的(交集)                  │
│  EXCEPT        左边有、右边没有的(差集)          │
│  ... ALL       保留重复行(不去重)                │
│                                                  │
│  ⚠️  列数必须相同,按位置比较                     │
│  ⚠️  默认去重(DISTINCT 行为)                    │
│  ⚠️  MySQL 8.0+ 才支持                           │
│  ⚠️  比 NOT IN 更安全(自动处理 NULL)            │
└──────────────────────────────────────────────────┘

最后说两句

EXCEPT 和 INTERSECT 不是什么高深语法。它们只是太简单了,简单到很多人忽略了。

但好的 SQL 不是写得复杂——是写得简单,让下一个看代码的人 3 秒钟就能理解你在干什么,那些好用但是少见的SQL函数。


该文章在 2026/5/27 18:25:28 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-1  粤公网安备44030602007207号