Reputation: 1363
I'm making a stock ticker as a learning experience for PostgreSQL and AngularJS.
In my ticker query, I attempt to discover the change in price from the previous day. I'm implementing the DB queries in PHP right now for ease of testing and I'll port to AngularJS later.
DB Setup
prices
--pk
--fund (foreign key to funds.pk)
--price
--price_date
funds
--pk
--fund_name
--summary
Query Get the latest price and the price before it (as well as other info) for each fund with an entry in the prices table. This $query is a single line in my PHP file.
$query = 'SELECT prices.price_date,
prices.price,
(lag(prices.price) over (ORDER BY prices.price_date DESC)) as last_price,
prices.fund,
funds.fund_name
FROM prices
INNER JOIN funds ON prices.fund=funds.pk
WHERE price_date=(SELECT price_date FROM prices ORDER BY price_date DESC LIMIT 1)';
Result
[
{"price_date":"2015-09-08","price":"17.5901","last_price":null,"fund":"1","fund_name":"L Income"},
{"price_date":"2015-09-08","price":"22.8859","last_price":"17.5901","fund":"2","fund_name":"L 2020"},
{"price_date":"2015-09-08","price":"24.6693","last_price":"22.8859","fund":"3","fund_name":"L 2030"},
{"price_date":"2015-09-08","price":"26.1456","last_price":"24.6693","fund":"4","fund_name":"L 2040"},
{"price_date":"2015-09-08","price":"14.7756","last_price":"26.1456","fund":"5","fund_name":"L 2050"},
{"price_date":"2015-09-08","price":"14.8181","last_price":"14.7756","fund":"6","fund_name":"G Fund"},
{"price_date":"2015-09-08","price":"16.93","last_price":"14.8181","fund":"7","fund_name":"F Fund"},
{"price_date":"2015-09-08","price":"26.369","last_price":"16.93","fund":"8","fund_name":"C Fund"},
{"price_date":"2015-09-08","price":"35.9595","last_price":"26.369","fund":"9","fund_name":"S Fund"},
{"price_date":"2015-09-08","price":"24.0362","last_price":"35.9595","fund":"10","fund_name":"I Fund"}
]
As you can see, the lag() window function is only drawing on the current resultset for pulling the previous record's prices.price field.
I am at a loss now. Does anyone have guidance?
Upvotes: 0
Views: 549
Reputation: 1270513
I am guessing that you want the previous day's price for the fund
. This requires a partition by
clause:
SELECT p.price_date, p.price,
lag(p.price) over (PARTITION BY p.fund ORDER BY p.price_date DESC) as last_price,
p.fund, p.fund_name
FROM prices p INNER JOIN
funds f
ON p.fund = f.pk ;
If you then want this only for the last date, then use a subquery:
SELECT pf.*
FROM (SELECT p.price_date, p.price,
lag(p.price) over (PARTITION BY p.fund ORDER BY p.price_date DESC) as last_price,
p.fund, p.fund_name
FROM prices p INNER JOIN
funds f
ON p.fund = f.pk
) pf
WHERE price_date = (SELECT price_date FROM prices ORDER BY price_date DESC LIMIT 1);
The WHERE
clause is evaluated before the analytic functions, so the filtering affects which record (if any) is chosen by the LAG()
. Note: this assumes that the max price_date
is the same for all funds, but this is the logic in the question.
Upvotes: 1
Reputation: 49260
If you need to compare it to the price from previous day, you should use a conditional so it always picks up values from the previous day.
SELECT prices.price_date,
prices.price,
case when price_date = (select max(prices_date) from prices) then
lag(prices.price) over (ORDER BY prices.price_date)
end as last_price,
prices.fund,
funds.fund_name
FROM prices
INNER JOIN funds ON prices.fund = funds.pk
WHERE price_date=(SELECT price_date FROM prices ORDER BY price_date DESC LIMIT 1)
Upvotes: 0