【问题标题】:Selecting first and last row within a time interval在时间间隔内选择第一行和最后一行
【发布时间】:2015-03-13 07:14:18
【问题描述】:

我有一个名为 trades 的表,用于保存具有以下架构的货币交易数据:

id        - uuid
timestamp - timestamp without time zone
price     - numeric

我希望能够以可以构建蜡烛图的方式进行查询。为此,我需要 第一价最后价最高价最低价,按以下方式分组时间间隔。到目前为止,我有这个:

CREATE FUNCTION ts_round( timestamptz, INT4 ) RETURNS TIMESTAMPTZ AS $$
SELECT 'epoch'::timestamptz
     + '1 second'::INTERVAL * ( $2 * ( extract( epoch FROM $1 )::INT4 / $2 ) );
$$ LANGUAGE SQL;

SELECT ts_round( timestamp, 300 ) AS interval_timestamp
     , max(price) AS max, min(price) AS min
FROM trades
GROUP BY interval_timestamp
ORDER BY interval_timestamp DESC

我如何在这些时间间隔内获得第一价最后价

【问题讨论】:

  • 您如何定义first pricelast price?按时间戳?
  • 我严重怀疑您的功能是否符合您的实际需求。在 四舍五入 到整秒之后,它实际上是 截断n 秒的间隔。我怀疑您真的想将 舍入到 n 秒间隔。对吗?
  • 欧文,感谢您的反馈!您能否建议如何改进该功能?或者我应该为此创建一个新问题?
  • @MattBeedle:它到底应该做什么?

标签: sql postgresql aggregate-functions greatest-n-per-group window-functions


【解决方案1】:

我认为这是您想要的查询:

SELECT ts_round( timestamp, 300 ) AS interval_timestamp,
       max(firstprice) as firstprice,
       max(lastprice) as lastprice,
       max(price) AS maxprice, min(price) AS minprice
FROM (SELECT t.*,
             first_value(price) over (partition by ts_round(timestamp, 300) order by timestamp) as firstprice,
             first_value(price) over (partition by ts_round(timestamp, 300) order by timestamp desc) as lastprice
      FROM trades t
     ) t
GROUP BY interval_timestamp
ORDER BY interval_timestamp DESC;

【讨论】:

  • 可以在同一查询级别上对聚合函数的结果使用窗口函数,但反之则不行。虽然min()max() 可用于任一目的,但first_value()last_value() 是专用的窗口函数。这是句法废话,您需要一个子查询才能使其工作。不过,似乎并没有阻止人们投票。
  • 仍然不正确修复后。窗框的默认框架定义为ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。在您的子查询中,您有效地将 current 行的价格设为lastprice。在外部查询中的max(lastprice) 之后,您实际上第二次返回max(price),这是无稽之谈。仍然没有阻止人们投票。
  • @ErwinBrandstetter 。 . .谢谢你们的cmets。
  • 您可以在同一个窗口函数上调用 first_value 和 last_value,而不是调用两次 first_value。查询会更快。
【解决方案2】:

这对所有窗口函数使用一个单个窗口,并且没有子查询。应该比当前接受的答案更快。

SELECT DISTINCT ON (1)
       ts_round(timestamp, 300) AS interval_timestamp
     , min(price)         OVER w AS min_price
     , max(price)         OVER w AS max_price
     , first_value(price) OVER w AS first_price
     , last_value(price)  OVER w AS last_price
FROM   trades
WINDOW w AS (PARTITION BY ts_round(timestamp, 300) ORDER BY timestamp
             ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
ORDER  BY 1 DESC;

要根据timestamp 定义“第一个”和“最后一个”,此列必须是唯一的,否则查询不明确,并且您可以从同等同行中任意选择。

自定义窗口框架的解释类似的答案:

用序号表示的说明:

另外:不要使用“时间戳”作为标识符。这是一个基本类型名称,容易出错。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    • 2016-04-08
    • 2015-06-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多