I have the following schema:
expenses
id | name, varchar | cost, double | date, DATE | category_id, int f_key | user_id, int f_key |
---|---|---|---|---|---|
1 | Pizza | 22.9 | 22/08/2022 | 1 | 1 |
2 | Pool | 34.9 | 23/08/2022 | 2 | 1 |
categories
id | name, varchar |
---|---|
1 | Food |
2 | Leisure |
3 | Medicine |
4 | Fancy food |
users_categories(user_id int foreign key, category_id foreign key)
user_id int f_key | category_id int f_key |
---|---|
1 | 1 |
1 | 2 |
1 | 3 |
2 | 4 |
And two users with id 1 and 2.
Relation between user and category is many to many.
Problem:
I want to get statistics (total cost amount and count) for all categories. For categories where there are no expenses I want to return 0. Here is my query:
SELECT categories.name as name, count(expenses.name) as count, round(SUM(price)::numeric,2) as sum
FROM expenses
Right JOIN categories ON expenses.category_id = categories.id
and expenses.category_id in (
select users_categories.category_id from users_categories where users_categories.user_id = 1
)
and expenses.id in(
Select expenses.id from expenses
join users_categories on expenses.category_id = users_categories.category_id
and expenses.user_id = 1
AND (extract(year from date) = 2022 OR CAST(2022 AS int) is null)
AND (extract(month from date) = 8 OR CAST(8 AS int) is null)
)
GROUP BY categories.id ORDER BY categories.id
The response is:
name | count | sum |
---|---|---|
Food | 1 | 22.9 |
Leisure | 1 | 33.9 |
Medicine | 0 | null |
Fancy food | 0 | null |
How I should edit my query to eliminate the last row, because this category doesn't belong to the user 1.
CodePudding user response:
You want to move expenses.category_id in ...
out of the ON condition and into a WHERE clause.
When it is in the ON clause, that means rows which were removed by the in-test just get NULL-fabricated anyway. You want to remove those rows after the NULL-fabrication is done, so that they remain removed. But why do you use that in-test anyway? Seems like it would be much simpler written as another join.
CodePudding user response:
What I understood is you are trying to get the count and sum of expenses for all the categories related to the user_id 1 within the month of august 2022.
Please try out the following query.
WITH statistics AS (SELECT e.category_id, count(e.*) as count, round(sum(e.cost),2) as sum FROM expenses e WHERE e.user_id=1 AND (e.date BETWEEN '01/08/2022' AND '31/08/2022') GROUP BY e.category_id), user_category as(SELECT uc.category_id, COALESCE(s.count,0) as count, COALESCE(s.sum,0) as sum FROM users_categories uc LEFT JOIN statistics s ON uc.category_id=s.id WHERE uc.user_id=1) SELECT c.name, u.count, u.sum FROM categories c INNER JOIN user_category u ON u.category_id=c.id;