DISTINCT ON是PostgreSQL特有语法,用于每组保留排序后的首行;而DISTINCT是对整行全字段去重。DISTINCT ON必须与ORDER BY配合,且ORDER BY前导列须与DISTINCT ON列一致并同序。
DISTINCT ON 是什么,和普通 DISTINCT 有什么区别
DISTINCT ON 不是标准 SQL,是 PostgreSQL 特有的语法,用来在去重时保留“每组第一条”记录,而不是像 DISTINCT 那样对整行做全字段比对。它必须配合 ORDER BY 使用,且 ORDER BY 的前导列要和 DISTINCT ON 的列完全一致(顺序也要一致),否则会报错:SELECT DISTINCT ON expressions must match initial ORDER BY expressions。
典型场景是“每个用户取最新一条订单”“每个设备取最近一次上报”——这类需求用 GROUP BY 很难直接满足,因为非分组字段的聚合逻辑不明确;而 DISTINCT ON 能靠排序天然定义“最新”。
怎么写才能正确取出每组最新记录
核心是:把分组字段放在 DISTINCT ON 里,把时间戳/序号字段放在 ORDER BY 的后续位置,并按降序排(DESC)。
-
DISTINCT ON (user_id)表示“每个 user_id 只留一行” -
ORDER BY user_id, created_at DESC确保同一 user_id 下,created_at最大的那条排最前,被DISTINCT ON拿到 - 如果漏掉
user_id在ORDER BY的开头,会直接报错 - 如果
created_at允许 NULL,记得加NULLS LAST,避免 NULL 被当成“最新”
示例:
SELECT DISTINCT ON (user_id) * FROM orders ORDER BY user_id, created_at DESC NULLS LAST;
为什么不能只靠 ORDER BY + LIMIT 1?
单独用 ORDER BY created_at DESC LIMIT 1 只能取全局最新一条,不是“每组最新”。有人试图用子查询或窗口函数替代,但 DISTINCT ON 在多数情况下更简洁、可读性更高、执行计划也更可控。