【问题标题】:Grouped LIMIT in PostgreSQL: show the first N rows for each group, BUT only if the first of those row equals specific dataPostgreSQL 中的分组限制:显示每个组的前 N ​​行,但仅当这些行中的第一行等于特定数据时
【发布时间】:2021-02-27 12:27:05
【问题描述】:

考虑下表:

SELECT * FROM report_raw_data;
ts         | d_stamp    | id_mod | value
-----------+------------+--------+------
1605450647 | 2020-11-15 | 1      | 60
1605464634 | 2020-11-15 | 2      | 54
1605382126 | 2020-11-14 | 1      | 40
1605362085 | 2020-11-14 | 3      | 33
1605355089 | 2020-11-13 | 1      | 60
1605202153 | 2020-11-12 | 2      | 30

我需要的是获取按每个 id_mod 的 ts 排序的前两行,但前提是 d_stamp 是当前日期(在本例中为 2020-11-15)。

到目前为止,我已经设法让每个 id_mod 的前两行按 ts 排序,但我很难找到唯一的当前日期 2020-11-15。

这是我的错误结果尝试:

SELECT * FROM (SELECT ROW_NUMBER() OVER (PARTITION BY id_mod ORDER BY ts DESC) AS r,t.* FROM 
report_raw_data t) x WHERE x.r <= 2;

ts         | d_stamp    | id_mod | value
-----------+------------+--------+------
1605450647 | 2020-11-15 | 1      | 60
1605382126 | 2020-11-14 | 1      | 40
1605464634 | 2020-11-15 | 2      | 54
1605202153 | 2020-11-12 | 2      | 30
1605362085 | 2020-11-14 | 3      | 33

如果我在查询中使用 WHERE = '2020-11-15',我最终将只获得我需要的那些记录(因此没有第二行)。

这是我想要得到的(忽略 id_mod 编号 3),因为它是第一行不是从 2020-11-15 开始的:

ts         | d_stamp    | id_mod | value
-----------+------------+--------+------
1605450647 | 2020-11-15 | 1      | 60
1605382126 | 2020-11-14 | 1      | 40
1605464634 | 2020-11-15 | 2      | 54
1605202153 | 2020-11-12 | 2      | 30

还有一点需要注意:我需要能够在查询中使用 LIMIT 和 OFFSET 才能对前端的结果进行分页。

【问题讨论】:

    标签: sql postgresql datetime where-clause greatest-n-per-group


    【解决方案1】:

    从您当前的查询开始,一个简单的方法是在子查询中使用一个窗口MAX() 来根据id_mod 恢复最新的ts。然后,您可以将其用于外部查询中的其他过滤。

    SELECT * 
    FROM (
        SELECT t.*,
            ROW_NUMBER() OVER (PARTITION BY id_mod ORDER BY ts DESC) AS rn,
            MAX(ts)      OVER(PARTITION BY id_mod) max_ts
        FROM report_raw_data t
    ) x 
    WHERE rn <= 2 and max_ts = current_date;
    

    【讨论】:

    • @xyz83242:你不接受这个答案有什么原因吗?
    【解决方案2】:

    假设您没有未来的数据,我建议:

    SELECT rdr.*
    FROM (SELECT rdr.*,
                 ROW_NUMBER() OVER (PARTITION BY id_mod ORDER BY ts DESC) AS seqnum
          FROM report_raw_data rdr
          WHERE d_stamp = current_date
         ) rdr
    WHERE seqnum <= 2;
    

    基于子查询中的时间进行过滤应该会显着提高性能。为了获得最佳性能,您需要在(d_stamp, id_mod, ts desc) 上建立索引。

    【讨论】:

      猜你喜欢
      • 2010-11-10
      • 1970-01-01
      • 2020-01-31
      • 2016-12-12
      • 2018-07-08
      • 1970-01-01
      • 1970-01-01
      • 2022-11-15
      • 1970-01-01
      相关资源
      最近更新 更多