I am trying to find the name of students where a symmetric pair exists. There are 3 tables:
**student**
student_id (Primary Key) | smallint
student_name | varchar(30)
**mathematics_marks**
student_id (Primary Key) | smallint
score | float (5,2)
**science_marks**
student_id (Primary Key) | smallint
score | float (5,2)
with Functions as (
select s.student_name as name, mm.score as math_score, sm.score as science_score
from student s
join mathematics_marks mm
on mm.student_id = s.student_id
join science_marks sm
on sm.student_id = s.student_id)
select t1.name
from Functions t1
join Functions t2
on t1.math_score = t2.science_score
and t1.science_score = t2.math_score
where t1.math_score < t1.science_score
Edit from your comment: A student is called as being a part of a symmetric pair if the marks obtained by that student in science is equal to the marks obtained by some other student in mathematics and the marks obtained in mathematics are the same as marks obtained by the other student in science.
Advertisement
Answer
Given the structure of the data, I would assume that students could have multiple marks in each subject. Otherwise, why store the values in separate tables?
To solve this problem, I would preaggregate the marks:
with mm as (
select student_id, group_concat(score order by score desc) as math_scores
from mathematics_marks
group by student_id
),
sm as (
select student_id, group_concat(score order by score desc) as science_scores
from science_marks
group by student_id
),
sms as (
select *
from mm join
sm
using (student_id)
)
select sms.student_id, sms2.student_id
from sms join
sms sms2
on sms.math_scores = sms2.science_scores and
sms.science_scores = sms2.math_scores and
sms.student_id < sms2.student_id;
This returns the matching ids. You need an additional join if you want to bring in the names.
Note: You have stored the values as float
s. This is quite dangerous. You should be storing the values as decimal
/numeric
. Two values that look the same might actually be different.