J Szum
J Szum

Reputation: 515

Find students studying two subjects with three different roles SQL

I have a table students with student id, subjects and number of roles per subject. How to find students who studied at least two subjects where they had exactly three roles?

student    subject    num_roles
1000       223        2
1000       223        1
-------------------------------
1043       243        3
-------------------------------
1002       109        3
1002       230        3
1002       200        1            valid student
...

I can only think of finding students and their subjects that are equal to 3 num_roles. But how to modify the code to find students with 3 roles in at least 2 subjects?

SELECT s.student, s.subject
FROM students s
WHERE s.num_roles = 3 
ORDER BY s.student, s.subject; 

Expected output:

student     subject 
1002        109
1002        230
... 

Upvotes: 2

Views: 595

Answers (3)

Gordon Linoff
Gordon Linoff

Reputation: 1269753

If you are satisfied with one row per student, you can use array_agg() to combine the subjects:

SELECT s.student, ARRAY_AGG(s.subject) as subjects
FROM students s
WHERE s.num_roles = 3 
ORDER BY s.student, s.subject
HAVING COUNT(*) >= 2;

Upvotes: 1

Erwin Brandstetter
Erwin Brandstetter

Reputation: 656686

Simple and fast with EXISTS:

SELECT student, subject
FROM   students s1
WHERE  num_roles = 3
AND    EXISTS (  -- same student has another subject with 3 roles
   SELECT FROM students s2
   WHERE  s2.num_roles = 3
   AND    s2.student = s1.student
   AND    s2.subject <> s1.subject
   )
ORDER  BY 1,2;

A multicolumn index on (num_roles, student) would be the optimum for this query. (Typically, it won't pay to append the subject to the index.)

A query using GROUP BY & count() is more expensive and has to use a sequential scan of the whole table, plus another index (or sequential) scan. Test with EXPLAIN / EXPLAIN ANALYZE.

Upvotes: 1

Eugene
Eugene

Reputation: 1533

  Select student , subject 
  From students 
  where student in (
    Select student 
    From students 
    where num_roles = 3
    Group by student having count(subject) >1
  )
  and num_roles = 3

Upvotes: 1

Related Questions