我正在尝试查询PostgreSQL 8.4.2服务器中的表以获取开 - 高 - 低 - 关闭数据。该表和我的第一个查询如下。
问题: 有没有办法在不使用子查询的情况下获得相同的结果,如下面的示例查询中所示?也许使用FIRST_VALUE()或LAST_VALUE()窗口方法?
-- FIRST ATTEMPT AT OHLC
SELECT
contract_id
, TO_CHAR(ts, 'YYMMDDHH24MI')
, (SELECT price FROM fill minF WHERE minF.fill_id = MIN(f.fill_id)) AS open
, MAX(f.price) AS high
, MIN(f.price) AS low
, (SELECT price FROM fill maxF WHERE maxF.fill_id = MAX(f.fill_id)) AS close
FROM fill f
GROUP BY 1,2
ORDER BY 1,2;
-- SIMPLIFIED DDL
CREATE TABLE fill
(
contract_id SEQUENCE PRIMARY KEY
, ts TIMESTAMP
, price NUMERIC(10,4)
);
答案 0 :(得分:2)
我想得到分日决议。这似乎运作良好。
SELECT
contract_id
, the_minute
, open
, high
, low
, close
FROM
(
SELECT
contract_id
, TO_CHAR(ts, 'YYMMDDHH24MI') AS the_minute
, MIN(price) OVER w AS low
, MAX(price) OVER w AS high
, LAST_VALUE(price) OVER w AS open -- Note the window is in reverse (first value comes last)
, FIRST_VALUE(price) OVER w AS close -- Note the window is in reverse (last value comes first)
, RANK() OVER w AS the_rank
FROM fill
WINDOW w AS (PARTITION BY contract_id, TO_CHAR(ts, 'YYMMDDHH24MI') ORDER BY fill_id DESC)
) AS inr
WHERE the_rank = 1
ORDER BY 1, 2;
谢谢你,斯科特。你的回答帮助我找到了以下解决方案。
答案 1 :(得分:2)
我发现Timescale extension的PostgresSQL非常方便。它具有按任意时间间隔分组的功能。该函数称为time_bucket()
,并且具有与内置date_trunc()
函数相同的语法,但是采用间隔而不是时间精度作为第一个参数。无需使用窗口/分区。 Here,您可以找到其API文档。这是一个示例:
SELECT
time_bucket('1 minute', timestamp_) timebucket,
(array_agg(price ORDER BY timestamp_ ASC))[1] open,
MAX(price) high,
MIN(price) low,
(array_agg(price ORDER BY timestamp_ DESC))[1] close,
SUM(turnover) turnover,
COUNT(*) nr_ticks
FROM price_tick
GROUP BY timebucket
ORDER BY timebucket
如果您要使用新的摄取数据自动更新“按时间间隔分组” 视图,并且还想查询这些视图,还可以查看continuous aggregate views频繁地这样可以节省大量资源,并使查询更快。
答案 2 :(得分:1)
你有你的分组到分钟。我将假设这是错误的,因为这些通常是在白天完成的。如果我错了,你将不得不改回来。
SELECT DISTINCT contract_id, ts::date,
min(price) OVER w,
max(price) OVER w,
first_value(price) OVER w,
last_value(price) OVER w
FROM fill
WINDOW w AS (PARTITION BY contract_id, ts::date ORDER BY ts)
ORDER BY 1,2
答案 3 :(得分:0)
我是这样解决的:
select FLOOR(MIN(ts) / :period) * :period as timestamp,
SUBSTRING_INDEX(MIN(CONCAT(ts, '_', price)), '_', -1) as open,
max(price) as high,
min(price) as low,
SUBSTRING_INDEX(MAX(CONCAT(ts, '_', price)), '_', -1) as close,
sum(amount) as volume
from uni_tx
where asset = :asset
and ts between :startTime and :endTime
GROUP BY FLOOR(ts / :period)
order by timestamp