You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL WHERE子查询优化:筛选含销售记录的用户目标数据

解决按Email优先选取销售记录或最早时间记录的SQL优化方案

嘿,针对你的需求,我给你整理了一个清晰高效的解决方案,刚好能利用你提到的「每个Email要么仅一条has_sales=1,要么全为0」这个前提来简化逻辑。

需求回顾

你需要从表中为每个Email筛选一条记录:

  • 优先选取该Email下has_sales=1的记录
  • 如果没有销售记录,就选该Email下timestamp最早的记录

优化后的SQL实现

我们可以用窗口函数ROW_NUMBER()来实现这个逻辑,这种写法比嵌套子查询更直观,性能也更出色:

SELECT uuid, email, timestamp, has_sales
FROM (
    SELECT 
        uuid, 
        email, 
        timestamp, 
        has_sales,
        -- 按Email分组,先按has_sales降序(1优先),再按时间升序
        ROW_NUMBER() OVER (
            PARTITION BY email 
            ORDER BY has_sales DESC, timestamp ASC
        ) AS row_rank
    FROM dup_mail
) ranked_records
WHERE row_rank = 1
ORDER BY email;

逻辑解释

  1. 分组处理:PARTITION BY email把数据按Email分成独立的组,每个组内单独执行排序逻辑。
  2. 优先级排序:ORDER BY has_sales DESC, timestamp ASC确保:
    • 所有has_sales=1的记录会排在同组的最前面(降序排序下1>0)
    • 如果某个Email全是has_sales=0的记录,就按timestamp升序排列,最早的记录自动排在第一位
  3. 筛选目标记录:ROW_NUMBER()会给每个组内的记录按排序结果编号,编号为1的就是我们需要的那条记录,外层查询只保留row_rank=1的行即可。

为什么比原SQL更好?

原SQL的子查询方式在数据量较大时可能会重复执行多次MIN(timestamp)的计算,而窗口函数的执行计划通常更高效,只需要一次扫描就能完成分组和排序,同时逻辑上更清晰,后续维护也更方便。

用你的示例数据测试的话,这个SQL会精准返回你预期的结果:

uuid email          timestamp           has_sales
3    a@gmail.com    2017-10-06 17:08:15 1
6    b@gmail.com    2016-10-02 10:28:23 1

内容的提问来源于stack exchange,提问作者Flavio de Falcao e Helena

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:54:10