I have tables named course
, student
and students_in
in a MySQL database. The tables look like this:
course
course_id name
3 Physics
12 English
19 Basket Weaving
4 Computer Science
212 Discrete Math
102 Biology
20 Chemistry
50 Robotics
7 Data Engineering
student
id name
2 Sally
1 Bob
17 Robert
9 Pierre
12 Sydney
41 James
22 William
5 Mary
3 Robert
92 Doris
6 Harry
students_in
course_id student_id grade
3 2 B
212 2 A
3 12 A
19 12 C
3 41 A
4 41 B
212 41 F
19 41 A
12 41 B
3 17 C
4 1 A
102 1 D
102 22 A
20 22 A
20 5 B
50 3 A
12 92 B
12 17 C
7 6 A
Here is a Fiddle: http://sqlfiddle.com/#!17/8d86ee/34
My goal is to get the id
and name
of the students who:
- have taken a course with Sally (i.e. "first-degree" relationship), OR
- have taken a course with someone who has taken a course with Sally (i.e. "second-degree" relationship), OR
- have taken a course with someone who has taken a course with someone who has taken a course with Sally (i.e. "third-relationship" relationship)
Essentially, we’re looking for first-, second-, and third-degree relationships to Sally.
Here is a depiction of what this looks like:
Since Sally took course IDs 3 and 212, the desired result would look like this (not the colorful table above, which I provided for illustration of the logic involved):
student_id student_name
12 Sydney <-- took course ID 3 with Sally
41 James <-- took course ID 3 and 212 with Sally
17 Robert <-- took course ID 3 with Sally
1 Bob <-- took course ID 4 with James
92 Doris <-- took course ID 12 with James and Robert
102 William <-- took course ID 102 with Bob
I tried to solve this problem by using a Common Table Expression (CTE) to query the first-degree relationships, and can probably use two additional CTEs to get the second-degree and third-degree relationships. But, this feels like a very inelegant way to do this.
Can someone please help with an elegant approach to this problem?
Thank you!
3
Answers
You can use a recursive
cte
:See fiddle.
A little verbose, but also a little more generalized than your try in that you can control the depth.
A few defensive additions: 1. Left join on student table in case no R.I. there. 2. Filter out Sally from the result (don’t care that Robert was with Sally and then Sally was with Robert)
Join’s repeated as many times as needed, also good, but perhaps less elegant:)