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

如何在PostgreSQL中获取每个用户-商品类别分组的前两条订单日期记录

解决方案:用窗口函数实现分组取前两条订单日期

要实现这个需求,我们可以借助PostgreSQL的窗口函数给每个用户+商品分类组内的订单按日期排序,再通过条件聚合把前两条日期转成对应列。具体实现如下:

1. 先给分组内的订单标记行号

首先用ROW_NUMBER()窗口函数,针对每个user_id和product_class的组合,按order_date从小到大给订单编号:

SELECT 
  user_id,
  product_class,
  order_date,
  -- 按用户+分类分组,组内按订单日期升序生成行号
  ROW_NUMBER() OVER (PARTITION BY user_id, product_class ORDER BY order_date) AS rn
FROM orders

这个子查询会把每个组里最早的订单标记为rn=1,第二早的标记为rn=2,以此类推。

2. 聚合提取前两条订单日期

基于上面的编号结果,我们用条件聚合把rn=1和rn=2的日期分别提取为first_order和second_order:

SELECT
  user_id,
  product_class,
  -- 取组内行号为1的订单日期(最早订单)
  MAX(CASE WHEN rn = 1 THEN order_date END) AS first_order,
  -- 取组内行号为2的订单日期,无此记录则返回NULL
  MAX(CASE WHEN rn = 2 THEN order_date END) AS second_order
FROM (
  SELECT
    user_id,
    product_class,
    order_date,
    ROW_NUMBER() OVER (PARTITION BY user_id, product_class ORDER BY order_date) AS rn
  FROM orders
) ranked_orders
-- 按用户+分类分组聚合
GROUP BY user_id, product_class
-- 按用户和分类排序,让结果更规整
ORDER BY user_id, product_class;

结果验证

执行这段SQL后,会得到完全符合你期望的结果:

user_idproduct_classfirst_ordersecond_order
0001automotive2019-04-232021-06-01
0001luxury goods2019-05-182022-07-03
0002automotive2018-12-03NULL
0002healthcare2018-09-172019-03-19
0002luxury goods2020-05-15NULL

补充说明

  • 这里用MAX()聚合是因为每个组内rn=1和rn=2最多各有一条记录,MAX()会直接返回对应的值,没有匹配记录时就保留NULL,用MIN()也能达到同样效果。
  • 如果你的订单日期存在重复,且需要把相同日期的订单都算作“第一条”,可以把ROW_NUMBER()换成RANK(),不过根据你的需求场景,ROW_NUMBER()已经足够满足要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 16:43:12