Postgres 窗口函数:对满足基于当前行的条件的窗口框架的记录应用聚合函数
Posted
技术标签:
【中文标题】Postgres 窗口函数:对满足基于当前行的条件的窗口框架的记录应用聚合函数【英文标题】:Postgres window functions: applying an aggregate function on a window frame's records that satisfy a condition based on the current row 【发布时间】:2020-12-25 15:48:03 【问题描述】:这个问题是关于 Postgres 12 的 SQL 语法的。
假设有一个stock_prices
表,其中包含以下列:ticker
、date
、price
。
我有兴趣在前 10 天的窗口上执行计算,例如:
SELECT
ticker,
date,
price,
AVG(price)
OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN 10 PRECEDING AND 1 PRECEDING) as avg_previous_10d
FROM stock_prices
除了上面的简单平均计算之外,我还想对前 10 天窗口内满足当前记录相关条件的记录执行计算。具体来说,在前 10 天窗口内:
计算价格高于当前行价格的次数 计算高于当前行价格的平均价格 查找价格第一次高于当前行的价格等等。
我知道我可以执行自联接,例如对this question 的回答。我的问题是 - 有没有一种使用窗口函数语法的简单方法来做到这一点?还是只有自行加入?
谢谢!
【问题讨论】:
【参考方案1】:听起来横向连接可能是最好的方法。以下假设您每天有一行:
SELECT sp.*, sp2.*
FROM stock_prices sp CROSS JOIN LATERAL
(SELECT AVG(sp2.price) as avg_previous_10d,
COUNT(*) FILTER (WHERE sp2.price > sp.price) as cnt_highest_previous_10day,
AVG(sp2.price) FILTER (WHERE sp2.price > sp.price) as avg_higher_previous_10day
FROM stock_prices sp2
WHERE sp2.ticker = sp.ticker AND
sp2.date >= sp.date - INTERVAL '10 DAY' AND
sp2.date < sp.date
) sp2;
这不是 100% 等同于您的查询,因为它使用 日历 时间。这可能是一个优势。但如果你想要完全等价的版本:
SELECT sp.*, sp2.*
FROM stock_prices sp CROSS JOIN LATERAL
(SELECT AVG(sp2.price) as avg_previous_10d,
COUNT(*) FILTER (WHERE sp2.price > sp.price) as cnt_highest_previous_10day,
AVG(sp2.price) FILTER (WHERE sp2.price > sp.price) as avg_higher_previous_10day
FROM (SELECT sp2.*
FROM stock_prices sp2
WHERE sp2.ticker = sp.ticker AND
sp2.date < sp.date
ORDER BY sp2.date DESC
LIMIT 10
) sp2
) sp2;
【讨论】:
【参考方案2】:你为什么不用self join
如下:
SELECT count(1) as num_times,
Avg(s10.price) as avg_price,
Min(s10.date) as first_time_higher_price
FROM stock_prices scur
Join stock_prices s10 on s10.ticker = scur.ticker
Where scur.date = current_date
And s10.date >= current_date - interval '10 day'
And s10.date < current_date
And s10.price >= scur.price
【讨论】:
以上是关于Postgres 窗口函数:对满足基于当前行的条件的窗口框架的记录应用聚合函数的主要内容,如果未能解决你的问题,请参考以下文章
过去 30 天的平均值,不包括当前记录(混合日期和基于行的条件)