You need to enable JavaScript to run this app. PostgreSQL单查询实现:获取全部pending状态draws及最新draw记录
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL单查询实现:获取全部pending状态draws及最新draw记录

问题根因

你之前的UNION语句没跑出预期结果,本质是踩了两个SQL解析的规则坑:

  • 没有括号隔离独立子查询时,UNION语句末尾的ORDER BY ... LIMIT会被引擎解析为对两个分支合并后的全量结果做排序截断,根本不会给第二个查询分支单独排序取最新记录,执行逻辑完全偏离预期。
  • UNION默认会自动合并两个分支返回的完全重复行:如果最新的那条记录本身已经属于pending集合,重复行只会被保留一次。这个行为通常不影响业务结果,但在大表场景下会带来不必要的去重排序开销。
调整实现方案

最小改动修正原写法

只需要给取最新记录的分支加一层括号,把排序、截断的逻辑完全限制在子查询内部,让引擎不会把ORDER BY的作用范围错配到整个UNION结果集:

SELECT * FROM draws WHERE state = 'pending'
UNION
(SELECT * FROM draws ORDER BY created_at DESC LIMIT 1);

注意:两种连接方式的差异可以根据业务需要选择:

  • 用UNION:自动合并两个分支返回的完全重复行,结果集无重复,但大表下会产生去重排序的额外开销;
  • 用UNION ALL:不做去重直接拼接结果,查询性能更高,但如果最新记录本身已经属于pending集合,会返回两条完全相同的行。

跨数据库兼容的窗口函数写法

部分早期版本的数据库(比如MySQL 5.x之前的版本)对UNION分支里的括号子查询支持不完善,这时候可以用窗口函数打标记的方式实现同样逻辑,完全不受SQL解析优先级的影响:

SELECT id, created_at, state
FROM (
    SELECT 
        id, 
        created_at, 
        state,
        -- 逐行标记:是否属于pending状态集合
        CASE WHEN state = 'pending' THEN 1 ELSE 0 END AS is_pending,
        -- 逐行标记:按创建时间倒序的行号,值为1即为全表最新记录
        ROW_NUMBER() OVER (ORDER BY created_at DESC) AS latest_row_num
    FROM draws
) t
WHERE is_pending = 1 OR latest_row_num = 1;

内容的提问来源于stack exchange,提问作者ThreeAccents

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.03 12:36:02