Reputation: 27852
I have the following query that basically tells me the status of a user related to the exams he has done:
SELECT users.id,
CASE WHEN users.closed_at IS NOT NULL
THEN 'closed'
WHEN COUNT(exams.id) FILTER(users.closed_at IS NOT NULL OR requests.finished_at IS NOT NULL) = COUNT(exams.id)
THEN 'completed'
WHEN COUNT(exams.id) FILTER(users.closed_at IS NOT NULL OR requests.finished_at IS NOT NULL) = 0
then 'not-completed'
ELSE 'in-progress'
END AS user_status
LEFT JOIN exams ON exams.user_id = users.id
This works fine, but now I also want to be able to filter depending on the exam status of the user, taking into account that I should be able to filter by multiple statuses. I have been suggested to do this with a subquery, so assuming I want to find the users which exam status is closed or 'not-completed', I have tried this:
SELECT users.id,
CASE WHEN users.closed_at IS NOT NULL
THEN 'closed'
WHEN COUNT(exams.id) FILTER(users.closed_at IS NOT NULL OR requests.finished_at IS NOT NULL) = COUNT(exams.id)
THEN 'completed'
WHEN COUNT(exams.id) FILTER(users.closed_at IS NOT NULL OR requests.finished_at IS NOT NULL) = 0
then 'not-completed'
ELSE 'in-progress'
END AS user_status
LEFT JOIN exams ON exams.user_id = users.id
WHERE (
SELECT
CASE WHEN users.closed_at IS NOT NULL
THEN 'closed'
WHEN COUNT(exams.id) FILTER(users.closed_at IS NOT NULL OR requests.finished_at IS NOT NULL) = COUNT(exams.id)
THEN 'completed'
WHEN COUNT(exams.id) FILTER(users.closed_at IS NOT NULL OR requests.finished_at IS NOT NULL) = 0
then 'not-completed'
ELSE 'in-progress'
END AS user_status_in_inner_query
) user_status_in_inner_query = 'closed' OR user_status_in_inner_query = 'not-completed'
But it throws an error saying 'aggregate functions are not allowed in WHERE'. How can I do this?
Upvotes: 0
Views: 932
Reputation:
Don't repeat the query in the WHERE
clause, put everything into a derived table, then you can use the alias:
select *
from (
SELECT users.id,
CASE
WHEN users.closed_at IS NOT NULL THEN 'closed'
WHEN COUNT(exams.id) FILTER(users.closed_at IS NOT NULL OR requests.finished_at IS NOT NULL) = COUNT(exams.id)
THEN 'completed'
WHEN COUNT(exams.id) FILTER(users.closed_at IS NOT NULL OR requests.finished_at IS NOT NULL) = 0
then 'not-completed'
ELSE 'in-progress'
END AS user_status
FROM users --<<< Seems to be missing in your query
LEFT JOIN exams ON exams.user_id = users.id
) t
where user_status in ('closed', 'not-completed');
Upvotes: 1
Reputation: 8572
I expect something like this will work?
SELECT id, user_status
FROM (
SELECT users.id,
CASE WHEN users.closed_at IS NOT NULL
THEN 'closed'
WHEN COUNT(exams.id) FILTER(users.closed_at IS NOT NULL OR requests.finished_at IS NOT NULL) = COUNT(exams.id)
THEN 'completed'
WHEN COUNT(exams.id) FILTER(users.closed_at IS NOT NULL OR requests.finished_at IS NOT NULL) = 0
then 'not-completed'
ELSE 'in-progress'
END AS user_status
LEFT JOIN exams ON exams.user_id = users.id
) xx
WHERE user_status IN ('closed', 'not-completed')
Basically just take your original query as the subquery, and do a standard select on that with whatever filters you want.
Upvotes: 1