【问题标题】:postgres: get earliest and latest record per day in linear timepostgres:以线性时间获取每天最早和最新的记录
【发布时间】:2019-04-03 16:08:09
【问题描述】:

我有一个带有列的表。其中之一是时间戳。该时间戳有一个索引。是否有有效的查询(大数据)让我每天获取最小和最大行?结果必须包括所有其他列。

或者唯一的方法是进行嵌套查询?某事喜欢:

select * from 
   (select min(timestamp),max(timestamp) from table
   group by day)
where timestamp in (min, max)

还是编写我自己的自定义 postgres 聚合?

【问题讨论】:

  • 两次 NOT EXISTS(),或两次 RANK()。 (并且不要将您的列命名为timestamp 或您的表table
  • 你的表有主键吗? (例如 id/identity 列)
  • 如果需要我可以拥有。我可以定义表格

标签: sql postgresql


【解决方案1】:

你可以在(timestamp::date, timestamp)上创建一个索引,然后试试:

select timestamp::date, min(timestamp), max(timestamp)
from t
group by timestamp::date;

我认为这将使用索引。

如果您需要所有列,请尝试使用两个索引:

  • (timestamp::date, timestamp)
  • (timestamp::date, timestamp desc)

然后做:

(select distinct on (timestamp::date) t.*
 from t
 order by timestamp::date, timestamp asc
) union all
(select distinct on (timestamp::date) t.*
 from t
 order by timestamp::date, timestamp desc
)

【讨论】:

  • 但我需要所有的列。这将只返回时间戳
【解决方案2】:

使用不存在():


select *
from ztable t0
where not exists (
        select * from ztable t1
        WHERE t1.ztimestamp::date = t0.ztimestamp::date
        AND t1.ztimestamp < t0.ztimestamp
        )
or not exists (
        select * from ztable t2
        WHERE t2.ztimestamp::date = t0.ztimestamp::date
        AND t2.ztimestamp > t0.ztimestamp
        )
        ;

,或者,使用窗口函数:


select t0.*
from ztable t0
JOIN ( select timestamp
        , row_number()OVER (GROUP BY ztimestamp::date ORDER BY ztimestamp ASC) AS rn1
        , row_number()OVER (GROUP BY ztimestamp::date ORDER BY ztimestamp DESC) AS rn2
        ) tx ON tx.ztimestamp = t0.ztimestamp
WHERE tx.rn1=1 OR tx.rn2=1
        ;

【讨论】:

    【解决方案3】:

    您可以将表加入您的子查询:

    select t.*
    from table t
    inner join (
      select min(timestamp) mint, max(timestamp) maxt 
      from table 
      group by timestamp::date
    ) g on (g.mint = t.timestamp or g.maxt = t.timestamp)
    

    编辑
    如果有像id 这样的唯一列,那么:

    with cte as (
      select t.*
      from table t
      inner join (
        select min(timestamp) mint, max(timestamp) maxt 
        from table 
        group by timestamp::date
      ) g on (g.mint = t.timestamp or g.maxt = t.timestamp)
    )
    select t.* from cte t
    where not exists (
      select 1 from cte
      where id < t.id and (mint = t.mint or maxt = t.maxt)
    )
    

    【讨论】:

    • 如果我们有多个具有相同时间戳的记录,这将返回所有记录。有没有办法每天只得到一分钟和一分钟?哪个都无所谓
    • 那会是哪一行?在什么条件下?你不能随便挑一行。是否有一个独特的列。因为也许这可以通过将上述代码作为另一个查询中的子查询来完成。
    • '不管哪个'。如果特定日期有很多行带有最大/最小时间戳,我需要选择其中任何一个。它可以是第一个,最后一个,无论哪个
    • 我定义了表格,所以如果需要的话可以有
    最近更新 更多