Reputation: 3245
This question is about SQL syntax for Postgres 12.
Let's assume a stock_prices
table with the following columns: ticker
, date
, price
.
I'm interested in performing calculation on the previous 10-day window, such as:
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
In addition to the simple average calculation above, I'd like to perform calculations on records within the previous 10-day window that satisfy conditions related to the current record. Specifically, within the previous 10-day window:
And so on.
I understand that I could perform a self join, such as the answer to this question. My question is - is there a straightforward way to do this using the window functions syntax? Or is self join the only way to go?
Thanks!
Upvotes: 0
Views: 219
Reputation: 35910
Why don't you use self join
as follows:
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
Upvotes: 0
Reputation: 1269983
It sounds like a lateral join might be the best approach. The following assumes you have one row for each day:
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;
This is not 100% equivalent to your query, because it uses calendar time. That might be an advantage. But if you want the version that is exactly equivalent:
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;
Upvotes: 0