Home > Enterprise >  SQL: Join 3 columns
SQL: Join 3 columns

Time:11-27

I have 3 tables:

  1. Profiles:
id created_at full_name invited_by invite_count is_admin avatar_url email
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]
  1. 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
  1. 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;
  •  Tags:  
  • sql
  • Related