I have the following table which stores historical prices for stocks
stock_id | open | close | high | low | timestamp
---------- -------- -------- -------- -------- ---------------------
2 | 338 | 330 | 338 | 330 | 2022-10-21 05:30:00
2 | 341 | 338 | 341 | 338 | 2022-10-20 05:30:00
2 | 340.05 | 340 | 341 | 340 | 2022-10-19 05:30:00
2 | 357 | 340 | 357 | 340 | 2022-10-18 05:30:00
2 | 358 | 358 | 358 | 358 | 2022-10-12 05:30:00
I want to get the 1 day change from the previous day by using values of last 2 record and window function LAG()
so I came up with the following query
SELECT stock_id,
close as last_price,
timestamp::DATE,
LAG(close) OVER (PARTITION BY stock_id
ORDER BY timestamp desc) AS one_day_change
FROM historical_prices WHERE stock_id = 2;
But this me all the change not just the latest record
stock_id | last_price | timestamp | one_day_change
---------- ------------ ------------ ----------------
2 | 330 | 2022-10-21 |
2 | 338 | 2022-10-20 | 330
2 | 340 | 2022-10-19 | 338
What I want instead is this
stock_id | last_price | timestamp | one_day_change
---------- ------------ ------------ ----------------
2 | 330 | 2022-10-21 | 338
What would be the best way to accomplish this? Maybe LAG()
is not suitable for this usecase?
CodePudding user response:
Limit to just the first (i.e., chronologically latest) result.
SELECT stock_id,
close as last_price,
timestamp::DATE,
LAG(close) OVER (PARTITION BY stock_id
ORDER BY timestamp desc) AS one_day_change
FROM historical_prices
WHERE stock_id = 2
ORDER BY timestamp desc
LIMIT 1;
CodePudding user response:
A window function doesn't reduce the number of result rows like an aggregate function does. It just adds another column to the result set.
You should sort ascending by timestamp
, so that lag
means the previous day. Then add an outer query that only selects the row with the latest timestamp:
SELECT stock_id, last_price, timestamp, one_day_change
FROM (SELECT stock_id,
close as last_price,
timestamp::DATE AS timestamp,
LAG(close) OVER (ORDER BY timestamp) AS one_day_change
FROM historical_prices
WHERE stock_id = 2) AS subq
ORDER BY timestamp DESC
FETCH FIRST 1 ROWS ONLY;