在时间间隔内选择第一行和最后一行
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 分钟的时间间隔.我还添加了时间间隔的交易量,因为,为什么不呢?
我有一个名为 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 分钟的时间间隔.我还添加了时间间隔的交易量,因为,为什么不呢?