在时间间隔内选择第一行和最后一行

Selecting first and last row within a time interval

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

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

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

CREATE FUNCTION ts_round( timestamptz, INT4 ) RETURNS TIMESTAMPTZ AS $$
SELECT 'epoch'::timestamptz
     + '1 second'::INTERVAL * (  * ( extract( epoch FROM  )::INT4 /  ) );
$$ 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

如何获得这些区间内的首价最后价格

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

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;

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

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 定义 "first" 和 "last",此列必须是唯一的,否则查询不明确,你会从平等的同行中任意选择。

关于自定义 window 框架的类似答案和解释:

  • Given time/interval to calculate open/high/low/close value in each grouped data

序号引用说明:

  • When can we use an identifier number instead of its name in PostgreSQL?

旁白:不要使用 "timestamp" 作为标识符。这是一个基本的类型名称,容易出错。

这也可以在不创建混淆函数的情况下完成,只需使用带有 unix 时间戳的 built-in floor 函数。

SELECT symbol, timestamp AS interval_timestamp,
   max(firstprice) as firstprice,
   max(lastprice) as lastprice,
   max(price) AS maxprice, min(price) AS minprice, 
   max(vol)-min(vol) as volume
FROM (SELECT t.*,
first_value(price) over (partition by 
floor(unix_timestamp(timestamp)/(5*60)) order by timestamp) as 
firstprice,
first_value(price) over (partition by 
floor(unix_timestamp(timestamp)/(5*60)) order by timestamp desc) as 
lastprice
  FROM trades t
 ) t
GROUP BY floor(unix_timestamp(timestamp)/(5*60))
ORDER BY timestamp

请注意,您在这里将时间戳转换为 unix 时间戳(如果您存储的是 unix timestmaps,则无需转换),然后将其除以分钟数 * 60。因此,在此示例中,我们返回 5 分钟的时间间隔.我还添加了时间间隔的交易量,因为,为什么不呢?