I've got a table with user id, balance (amount only increases) and date created. So, each month I can get last amount by user and date created.
I'm doing it like that:
SELECT balance
FROM balances
WHERE id IN (
SELECT max(id)
FROM balances
WHERE "userId" = 123
AND datecreated IN (
SELECT max(datecreated)
FROM balances
WHERE "userId" = 123
AND EXTRACT(YEAR FROM date(datecreated)) = 2018
AND EXTRACT(MONTH FROM date(datecreated))::integer = 8
)
)
First question: can it be done somehow better?
Second question: I can find the income by finding difference between current month last balance and previous month last balance.
SELECT (
SELECT balance
FROM balances
WHERE id IN (
SELECT max(id)
FROM balances
WHERE "userId" = 123
AND datecreated IN (
SELECT max(datecreated)
FROM balances
WHERE "userId" = 123
AND EXTRACT(YEAR FROM date(datecreated)) = 2018
AND EXTRACT(MONTH FROM date(datecreated))::integer = 8
)
) - (
SELECT balance
FROM balances
WHERE id IN (
SELECT max(id)
FROM balances
WHERE "userId" = 123
AND datecreated IN (
SELECT max(datecreated)
FROM balances
WHERE "userId" = 123
AND EXTRACT(YEAR FROM date(datecreated)) = 2018
AND EXTRACT(MONTH FROM date(datecreated))::integer = 7
)
)
) AS "month_income";
It works when I've got data for previous balance. But How can I select 0 if there is nothing in previous month? Tried to do CASE like:
SELECT
CASE WHEN balance IS NULL THEN 0
ELSE balance
END AS balance
FROM balances
WHERE id IN ( ... )
It does not return anything (even NULL value) when, for example, I'm setting WHERE id IN NULL. Also tried COALESCE (balance, 0). But the problem is that nothing returned.
Best Answer
If there is exactly one maximum balance per month, the first query can be simplified to
The difference between a specific month and the previous one, can be calculated with a window function:
Online example: https://rextester.com/WGTPBO61473