I have 3 tables:
- Profiles:
id | created_at | full_name | invited_by | invite_count | is_admin | avatar_url | |
---|---|---|---|---|---|---|---|
9e4d5874-1482-41e2-a481-d29ce38b5b67 | 2022-11-25 15:53:51.642357 00 | Admin user | true | [email protected] | |||
0f0cf390-5952-4fd6-a436-1d384a2c61b7 | 2022-11-25 15:53:51.642357 00 | Test user | 2 | false | [email protected] |
- Questions:
id | created_at | question | owner_id | group_id |
---|---|---|---|---|
d792c1b6-5578-4771-9192-08aeee3894c3 | 2022-11-25 17:11:54.031778 00 | 53w5 | 9e4d5874-1482-41e2-a481-d29ce38b5b67 | 00000000-0000-0000-0000-000000000000 |
3892d4ed-7ab0-4006-b983-ad7eaf0094d5 | 2022-11-25 17:17:45.133241 00 | test | 9e4d5874-1482-41e2-a481-d29ce38b5b67 | 2d76bc68-3f1b-4801-8d8d-65c3986ee7c0 |
ab3a0783-1fbe-4d8d-ac56-ce2bd01ff04a | 2022-11-25 18:03:56.078212 00 | test | 0f0cf390-5952-4fd6-a436-1d384a2c61b7 | 00000000-0000-0000-0000-000000000000 |
0c2a25ad-53d7-499a-8a6d-9b2ed5fde967 | 2022-11-25 18:11:50.776553 00 | www | 0f0cf390-5952-4fd6-a436-1d384a2c61b7 | 2d76bc68-3f1b-4801-8d8d-65c3986ee7c0 |
- Votes
user_id | question_id | created_at | answer | option_order |
---|---|---|---|---|
0f0cf390-5952-4fd6-a436-1d384a2c61b7 | 3892d4ed-7ab0-4006-b983-ad7eaf0094d5 | 2022-11-25 18:01:24.149577 00 | 1 | |
0f0cf390-5952-4fd6-a436-1d384a2c61b7 | d792c1b6-5578-4771-9192-08aeee3894c3 | 2022-11-25 18:01:29.606896 00 | 2 |
I want to construct the following table:
id | created_at | full_name | avatar_url | questions_published | votes_cast |
---|
I tried this:
SELECT profiles.id,
profiles.created_at,
profiles.full_name,
profiles.avatar_url,
count(questions.owner_id) AS questions_published,
count(votes.user_id) AS votes_cast
FROM public.profiles
LEFT JOIN public.questions
ON profiles.id = questions.owner_id
LEFT JOIN votes
ON profiles.id = votes.user_id
GROUP BY profiles.id;
The result looks like this:
id | created_at | full_name | avatar_url | questions_published | votes_cast |
---|---|---|---|---|---|
0f0cf390-5952-4fd6-a436-1d384a2c61b7 | 2022-11-25 15:53:51.642357 00 | Test user | 4 | 4 | |
9e4d5874-1482-41e2-a481-d29ce38b5b67 | 2022-11-25 15:53:51.642357 00 | Admin user | 2 | 0 |
but should looks like this:
id | created_at | full_name | avatar_url | questions_published | votes_cast |
---|---|---|---|---|---|
0f0cf390-5952-4fd6-a436-1d384a2c61b7 | 2022-11-25 15:53:51.642357 00 | Test user | 2 | 0 | |
9e4d5874-1482-41e2-a481-d29ce38b5b67 | 2022-11-25 15:53:51.642357 00 | Admin user | 2 | 2 |
CodePudding user response:
You are cross joining a users questions and votes. If a user asked two questions and cast two votes, you create four result rows of all combinations (2 x 2 = 4). If you count then, you will find four rows with questions and four rows with votes.
Instead, aggregate before joining, i.e. join the user's question count and vote count to their profile.
SELECT
p.id,
p.created_at,
p.full_name,
p.avatar_url,
COASLESCE(q.cnt, 0) AS questions_published,
COASLESCE(v.cnt, 0) AS votes_cast
FROM public.profiles p
LEFT JOIN
(
SELECT owner_id, COUNT(*) AS cnt
FROM public.questions
GROUP BY owner_id
) q ON q.owner_id = p.id
LEFT JOIN
(
SELECT user_id, COUNT(*) AS cnt
FROM votes
GROUP BY user_id
) v ON v.user_id = p.id
ORDER BY p.id;