Table of contents
Open Table of contents
Introduction
Relational algebra is a procedural query language that works on relations (tables) and produces relations as a result. It’s a fundamental concept in database theory, providing a theoretical foundation for SQL and other database query languages. It consists of a set of operations that take one or two relations as input and produce a new relation.
Data Operations
1. Students Relation
| StudentID | Name | Major |
|---|---|---|
| 101 | Alice | Computer Sci |
| 102 | Bob | Mathematics |
| 103 | Charlie | Computer Sci |
| 104 | David | Physics |
2. Enrollment Relation
| StudentID | CourseID | Grade |
|---|---|---|
| 101 | CS101 | A |
| 101 | MA101 | B+ |
| 102 | CS101 | B |
| 103 | PH101 | C |
| 104 | MA101 | A- |
1. Selection ()
The selection operation selects tuples (rows) from a relation that satisfy a given condition.
-
Notation:
-
Example: Find all students majoring in ‘Computer Sci’.
Result:
StudentID Name Major 101 Alice Computer Sci 103 Charlie Computer Sci
2. Projection ()
The projection operation selects specified attributes (columns) from a relation, removing duplicate tuples in the result.
-
Notation:
-
Example: Get the names and majors of all students.
Result:
Name Major Alice Computer Sci Bob Mathematics Charlie Computer Sci David Physics
3. Union ()
The union operation combines two relations that have the same number of attributes and compatible domains (schema).
It produces a relation containing all tuples that are in either of the original relations, removing duplicates.
-
Notation:
-
Example:
A example for union would be if we had two lists of students from different sources that we wanted to combine.
Creating a temporary relation for demonstration:
HonorsStudents(StudentID, Name, Major)StudentID Name Major 101 Alice Computer Sci 105 Eve Biology Result:
StudentID Name Major 101 Alice Computer Sci 103 Charlie Computer Sci 105 Eve Biology
4. Intersection ()
The intersection operation produces a relation containing all tuples that are common to both relations. Both relations must have the same schema.
-
Notation:
-
Example: Find students who are both in
Students(from our original table) and in theHonorsStudentstemporary table.Result:
StudentID Name Major 101 Alice Computer Sci
5. Set Difference ()
The set difference operation produces a relation containing all tuples that are in the first relation but not in the second relation. Both relations must have the same schema.
-
Notation:
-
Example: Find students who are in the
Studentstable but not in theHonorsStudentstable.Result:
StudentID Name Major 102 Bob Mathematics 103 Charlie Computer Sci 104 David Physics
6. Cartesian Product ()
Also known as Cross Join, this operation combines every tuple from the first relation with every tuple from the second relation.
If relation R has ‘m’ tuples and S has ‘n’ tuples, the result will have ‘m * n’ tuples. The schema of the result is the concatenation of the schemas of the two relations.
-
Notation:
-
Example: Combine
StudentsandEnrollment. (This usually produces a large, often meaningless, intermediate result without a subsequent selection for joining).Result (partial, would be 4 * 5 = 20 rows):
Students.StudentID Name Major Enrollment.StudentID CourseID Grade 101 Alice Computer Sci 101 CS101 A 101 Alice Computer Sci 101 MA101 B+ 101 Alice Computer Sci 102 CS101 B 101 Alice Computer Sci 103 PH101 C 101 Alice Computer Sci 104 MA101 A- … … … … … … 104 David Physics 104 MA101 A-
7. Join ()
The join operation combines tuples from two relations based on a common attribute or a join condition. The most common type is the Natural Join.
-
Natural Join Notation:
This joins relations
RandSon all common attributes, taking only one instance of each common attribute in the result. -
Example: Find the name and major of students along with the courses they are enrolled in and their grades.
Result:
StudentID Name Major CourseID Grade 101 Alice Computer Sci CS101 A 101 Alice Computer Sci MA101 B+ 102 Bob Mathematics CS101 B 103 Charlie Computer Sci PH101 C 104 David Physics MA101 A-
While the natural join (or inner join) only returns tuples that have matches in both relations, outer joins are designed to include tuples that might not have a match in the other relation, filling in NULL values where no match exists.
1. Students Relation
| StudentID | Name | Major |
|---|---|---|
| 101 | Alice | Computer Sci |
| 102 | Bob | Mathematics |
| 103 | Charlie | Computer Sci |
| 104 | David | Physics |
| 105 | Eve | Art |
2. Enrollment Relation
| StudentID | CourseID | Grade |
|---|---|---|
| 101 | CS101 | A |
| 101 | MA101 | B+ |
| 102 | CS101 | B |
| 103 | PH101 | C |
| 104 | MA101 | A- |
| 106 | AR101 | A |
| 101 | PH101 | B- |
7a. Left Outer Join ()
The Left Outer Join returns all tuples from the left relation and the matching tuples from the right relation. If a tuple in the left relation has no matching tuple in the right relation, the attributes from the right relation will be filled with NULL values.
-
Notation:
-
Example: Show all students and, if they are enrolled in any courses, show their enrollment details. Students without enrollment should still appear.
Result:
StudentID Name Major CourseID Grade 101 Alice Computer Sci CS101 A 101 Alice Computer Sci MA101 B+ 102 Bob Mathematics CS101 B 103 Charlie Computer Sci PH101 C 104 David Physics MA101 A- 101 Alice Computer Sci PH101 B- 105 Eve Art NULL NULL
7b. Right Outer Join ()
The Right Outer Join returns all tuples from the right relation and the matching tuples from the left relation. If a tuple in the right relation has no matching tuple in the left relation, the attributes from the left relation will be filled with NULL values.
-
Notation:
-
Example: Show all enrollments and, if they correspond to an existing student, show the student’s name and major. Enrollments by non-existent students should still appear.
Result:
StudentID Name Major CourseID Grade 101 Alice Computer Sci CS101 A 101 Alice Computer Sci MA101 B+ 102 Bob Mathematics CS101 B 103 Charlie Computer Sci PH101 C 104 David Physics MA101 A- 101 Alice Computer Sci PH101 B- 106 NULL NULL AR101 A
7c. Full Outer Join ()
The Full Outer Join returns all tuples from both the left and right relations. If a tuple in the left relation has no match in the right, or vice versa, the non-matching attributes will be filled with NULL values. It’s essentially the union of a Left Outer Join and a Right Outer Join.
-
Notation:
-
Example: Show all students and all enrollments. If a student has no enrollment, show their details with
NULLfor enrollment. If an enrollment has no matching student, show its details withNULLfor student information.Result:
StudentID Name Major CourseID Grade 101 Alice Computer Sci CS101 A 101 Alice Computer Sci MA101 B+ 102 Bob Mathematics CS101 B 103 Charlie Computer Sci PH101 C 104 David Physics MA101 A- 101 Alice Computer Sci PH101 B- 105 Eve Art NULL NULL 106 NULL NULL AR101 A
8. Rename ()
The rename operation is used to rename a relation or an attribute within a relation. This is useful for making expressions clearer or for distinguishing between attributes that have the same name in a join.
-
Notation: renames relation
RtoSand its attributes to . renames relationRtoS, keeping attribute names. renames attributeAtoBin relationR. -
Example 1 (Rename Relation): Rename the
Studentsrelation toUndergraduates.Result (same data, new relation name):
Undergraduatesrelation withStudentID,Name,Major. -
Example 2 (Rename Attribute): Rename
StudentIDtoStudent_IDin theStudentsrelation.Result:
Student_ID Name Major 101 Alice Computer Sci 102 Bob Mathematics 103 Charlie Computer Sci 104 David Physics
9. Assignment ( or )
The assignment operation allows you to store the result of a relational algebra expression into a new temporary relation variable. This is not a fundamental operation that produces a new type of result, but rather a way to break down complex queries into smaller, manageable steps and store intermediate results.
-
Notation:
TempRelation <- Expression -
Example: Find all students who are enrolled in
CS101and store this result in a new relation calledCS101_Students.Intermediate Result (
CS101_Enrollment):StudentID CourseID Grade 101 CS101 A 102 CS101 B You can then use
CS101_Enrollmentin subsequent operations:Final Result (Names of students in CS101):
Name Alice Bob
10. Division ()
The division operation is used when you want to find tuples in one relation that are related to all tuples in another relation. It’s often described as finding “A divided by B,” where A is a relation with attributes and B is a relation with attributes . The result contains attributes for which the corresponding values exist in A for every tuple in B.
This operation is particularly useful for “for all” type queries, such as “Find students who have taken all required courses.”
-
Notation:
-
Example: Find the
StudentIDs of students who have taken all courses listed inRequiredCourses(查找 R 中所有选择 S 的学生).Here:
- is our
Enrollmentrelation, with attributesStudentID(A) andCourseID(B). - is our
RequiredCoursesrelation, with attributeCourseID(B).
Let’s trace this:
-
Enrollment(R):StudentID CourseID Grade 101 CS101 A 101 MA101 B+ 102 CS101 B 103 PH101 C 104 MA101 A- 101 PH101 B- -
(R’ - our actual R for division):
StudentID CourseID 101 CS101 101 MA101 102 CS101 103 PH101 104 MA101 101 PH101 -
RequiredCourses(S):CourseID CS101 MA101
Now, we look for
StudentIDs inR'such that for eachCourseIDinS(CS101 and MA101), thatStudentIDis paired with thatCourseIDinR'.- Student 101: Has (101, CS101), (101, MA101), (101, PH101). Since (101, CS101) and (101, MA101) exist, Student 101 has taken all required courses.
- Student 102: Has (102, CS101). Does not have (102, MA101). So, 102 is excluded.
- Student 103: Has (103, PH101). Does not have (103, CS101) or (103, MA101). Excluded.
- Student 104: Has (104, MA101). Does not have (104, CS101). Excluded.
Result of Division:
StudentID 101 - is our
The division operation is powerful for specific types of “universal quantification” queries. While not as frequently used directly in SQL as other operations, its logic is crucial for understanding how certain complex SQL queries (often involving nested subqueries with NOT EXISTS or COUNT and GROUP BY) are constructed.
11. Group/Aggregation ()
The Group/Aggregation operation (often represented as or gamma) is an extension to basic relational algebra that allows for grouping tuples based on common attribute values and then applying aggregate functions (like COUNT, SUM, AVG, MAX, MIN) to each group. It is crucial for summarizing data.
-
Notation:
- : These are the grouping attributes. The relation will be partitioned into groups based on unique combinations of values in these attributes. If no grouping attributes are specified, the entire relation is treated as a single group.
- : These are the aggregate functions applied to attributes within each group. Common aggregate functions include:
- COUNT: Counts the number of tuples.
- SUM: Calculates the sum of values.
- AVG: Calculates the average of values.
- MAX: Finds the maximum value.
- MIN: Finds the minimum value.
-
Example 1: Counting Enrollments per Student Using our
Enrollmentrelation:StudentID CourseID Grade 101 CS101 A 101 MA101 B+ 102 CS101 B 103 PH101 C 104 MA101 A- 101 PH101 B- Goal: Count how many courses each student is enrolled in.
Result:
StudentID NumCourses 101 3 102 1 103 1 104 1 -
Example 2: Average Grade per Student Goal: Calculate the average grade for each student.
Result (assuming A=4, B+=3.5, B=3, C=2, A-=3.7, B-=2.5 for calculation):
StudentID AverageGrade 101 (4 + 3.5 + 2.5) / 3 = 3.33 102 3 / 1 = 3 103 2 / 1 = 2 104 3.7 / 1 = 3.7 (Note: The actual
Gradecolumn contains letter grades, soAVG(Grade)as a numerical average might not be directly applicable without a mapping function from letter grades to numbers. For demonstration, we assume such a mapping exists or thatGradecould be numerical.)
The Aggregation operator is a powerful tool for generating summary reports and answering analytical questions about the data, forming the basis for GROUP BY and aggregate functions in SQL.
Exercises
Exercise1
For table schemas S(Students), C(Courses) and SC(Student-Course Enrollment):
| S# | SNAME | AGE | SEX |
|---|---|---|---|
| 1 | Qiang Li | 23 | M |
| 2 | Li Liu | 22 | F |
| 5 | You Zhang | 22 | M |
| C# | CNAME | TEACHER |
|---|---|---|
| k1 | C Programming Language | Hua Wang |
| k5 | Database Principle | Jun Cheng |
| k8 | Compiler Principle | Jun Cheng |
| S# | C# | GRADE |
|---|---|---|
| 1 | k1 | 83 |
| 2 | k1 | 85 |
| 5 | k1 | 92 |
| 2 | k5 | 90 |
| 5 | k5 | 84 |
| 5 | k8 | 80 |
(1) Retrieve the Course ID (C#) and Course Name (CNAME) of courses taught by Jun Cheng.
(2) Retrieve the Student ID (S#) and Name (SNAME) of male students older than 21.
(3) Retrieve the names (SNAME) of students who have taken all courses taught by Jun Cheng.
- Find all Course IDs taught by Jun Cheng:
- Find all (S#, C#) pairs from enrollment:
- Divide student-course pairs by courses taught by ‘Jun Cheng’ to find S# of students who took all of them:
- Join with Students to get their names:
(4) Retrieve the Course IDs (C#) of courses not taken by student Qiang Li.
- Find the S# of ‘Qiang Li’:
- Find Course IDs taken by ‘Qiang Li’:
- Find all distinct Course IDs available:
- Subtract courses taken by ‘Qiang Li’ from all available courses:
(5) Retrieve the Course IDs (C#) of courses that have been selected by at least two students.
- Rename
SCto allow self-join and distinguish student IDs: , - Join
SC_1andSC_2on matchingC#but differentS#:
(6) Retrieve the Course IDs (C#) and Course Names (CNAME) of courses that all students have taken.
- Find all distinct Student IDs:
- Find all (C#, S#) pairs from enrollment:
- Divide course-student pairs by all students to find C# of courses taken by all students:
- Join with Courses to get their names:
(7) Retrieve the Student IDs (S#) of students who have taken at least one course taught by “Jun Cheng”.
- Find the Course IDs of courses taught by ‘Jun Cheng’:
- Join
SCwithR_1onC#and projectS#:
(8) Retrieve the Student IDs (S#) of students who have taken Course ‘k1’ and Course ‘k5’.
- Find S# of students who took ‘k1’:
- Find S# of students who took ‘k5’:
- Take the intersection of these two sets of S#:
(9) Retrieve the Student Names (SNAME) of students who have taken all available courses.
- Find all distinct Course IDs:
- Find all (S#, C#) pairs from enrollment:
- Divide student-course pairs by all courses to find S# of students who took all of them:
- Join with Students to get their names:
(10) Retrieve the Student IDs (S#) of students who have taken at least one of the courses taken by student ‘2’.
- Find Course IDs taken by student ‘2’:
- Join
SCwithR_1onC#and projectS#:
(11) Retrieve the Student IDs (S#) and Names (SNAME) of students who have taken the course named “C Programming Language”.
- Find the C# for ‘C Programming Language’:
- Join
SCwithR_1to find enrollments for ‘C Programming Language’: - Join
R_2withSto get student details and project S# and SNAME:
(12) Retrieve the Student IDs (S#) and Names (SNAME) of students who have not failed any course (assuming a failing grade is GRADE <= 60).
- Find the S# of students who have failed at least one course:
- Find all distinct S# from the Students table:
- Subtract students who failed from all students to get those who haven’t failed:
- Join with Students to get their names:
Exercise2
For Database Schema:
- Students (S): (S#, SNAME, SEX, MAJOR, SCHOLARSHIP)
- Courses (C): (C#, CNAME, CREDIT)
- Learning (L): (S#, C#, SCORE)
(1) Retrieve information for students majoring in “English”, including Student ID (S#), Name (SNAME), Course Name (CNAME), and Score (SCORE).
- Select students majoring in ‘English’:
- Join with Learning to get their course scores:
- Join with Courses to get course names:
- Project the required attributes:
(2) Retrieve Student ID (S#), Name (SNAME), Major (MAJOR), and Score (SCORE) for all students whose ‘Database Principles’ course score is greater than 90.
- Select the ‘Database Principles’ course:
- Join with Learning to find students who took this course and their scores:
- Filter for scores greater than 90:
- Join with Students to get student details:
- Project the required attributes:
(3) Retrieve Student ID (S#), Name (SNAME), and Major (MAJOR) for students who did not take course ‘C135’.
- Find Student IDs (S#) of students who did take course ‘C135’:
- Find all distinct Student IDs (S#) from the Students table:
- Subtract students who took ‘C135’ from all students to find those who didn’t:
- Join with Students to get their names and majors:
4. Retrieve the information (Student ID (S#), Name (SNAME), and Major (MAJOR)) of all students who did not fail any course (assuming a failing grade is SCORE < 60).
- Find the S# of students who have failed at least one course (SCORE < 60):
- Find all distinct S# from the
Studentstable: - Subtract students who failed from all students:
- Join with the
Studentstable to get their name and major, then project:
Exercise3
For Database Schema:
- Students (S): (S#, SNAME, SEX, MAJOR, SCHOLARSHIP)
- Courses (C): (C#, CNAME, CREDIT)
- Learning (L): (S#, C#, SCORE)
(1) Retrieve information for students majoring in “International Trade” and receiving a scholarship, including Student ID (S#), Name (SNAME), Course Name (CNAME), and Score (SCORE).
- Select students majoring in ‘International Trade’ and receiving a scholarship:
- Join with Learning to get their course scores:
- Join with Courses to get course names:
- Project the required attributes:
(2) Retrieve Course ID (C#), Name (CNAME), and Credit (CREDIT) for courses where a student achieved a perfect score (100).
- Select entries from Learning where SCORE is 100:
- Join with Courses to get course details:
- Project the required attributes (duplicates will be removed by projection):
(3) Retrieve Student ID (S#), Name (SNAME), and Major (MAJOR) for students who did not receive a scholarship and have at least one course score above 95.
- Find Student IDs (S#) of students who did not receive a scholarship:
- Find Student IDs (S#) of students with at least one score > 95:
- Find students who satisfy both conditions (intersection):
- Join with Students to get their names and majors:
(4) Retrieve Student ID (S#), Name (SNAME), and Major (MAJOR) for all students who have no course score below 80.
- Find Student IDs (S#) of students who do have at least one course score below 80:
- Find all distinct Student IDs (S#) from the Students table:
- Subtract students who have scores below 80 from all students:
- Join with Students to get their names and majors:
Here are the relational algebra expressions for the two problem sets, translated into English.
Exercise4
Database Schema:
- S (Students): (snum, sname, age, sex)
- SC (Student-Course): (snum, cnum, score)
- C (Courses): (cnum, cname, teacher)
(1) Retrieve the Course Numbers (cnum) of courses not taken by student “Xiang Liu”.
- Find the
snumof “Xiang Liu”: - Find the
cnumof courses taken by “Xiang Liu”: - Find all distinct
cnumfrom theCoursestable: - Subtract courses taken by “Xiang Liu” from all available courses:
(2) Retrieve the names (sname) of male students who have at least one course score above 90.
- Find the
snumof male students: - Find the
snumof students who have at least one course score above 90: - Intersect these two sets of
snumto find male students with scores > 90: - Join with
Studentsto get their names and project:
(3) List the names (sname) of students who did not select the course “Artificial Intelligence”.
- Find the
cnumfor “Artificial Intelligence”: - Find the
snumof students who did select “Artificial Intelligence”: - Find all distinct
snumfrom theStudentstable: - Subtract students who took “Artificial Intelligence” from all students:
- Join with
Studentsto get their names and project:
(4) Find the names (sname) of students who have taken all courses taught by “Teacher Yuan”.
- Find all
cnumtaught by “Teacher Yuan”: - Find all (
snum,cnum) pairs fromSC: - Perform division to find
snumof students who took all courses fromR_1: - Join with
Studentsto get their names and project:
(5) Find the names (sname) of students for whom every course score is above 70 AND their average score for all courses is above 75.
-
Part 1: Students whose every course score is above 70 (using standard relational algebra):
- Find
snumof students who have any score 70: - Find all
snumof students: - Students with all scores > 70:
- Find
-
Part 2: Students whose average score is above 75 (requires extended relational algebra with aggregation):
- Standard relational algebra does not include aggregation operators (like SUM, AVG, COUNT, GROUP BY) as primitive operations. However, most database courses introduce them as extensions. Assuming these extensions are allowed:
- Group
SCbysnumand calculate the average score: - Filter for students with
AvgScore> 75:
-
Combine and Final Result:
- Intersect the results from Part 1 and Part 2:
- Join with
Studentsto get their names and project:
Exercise5
Database Schema:
- S (Suppliers): (SNO, SNAME, STATUS, CITY)
- P (Parts): (PNO, PNAME, WEIGHT, COLOR)
- J (Projects): (JNO, JNAME, CITY)
- SPJ (Supply): (SNO, PNO, JNO, QTY)
(1) Provide the Supplier Numbers (SNO) of suppliers who supply Project J1.
(2) Provide all supply details (tuples from SPJ) where the quantity (QTY) is between 300 and 500 (inclusive).
(3) Provide the Part Numbers (PNO) of parts supplied by suppliers in ‘London’ to projects in ‘London’.
- Find
SNOof suppliers in ‘London’: - Find
JNOof projects in ‘London’: - Join
SPJwithR_1andR_2and projectPNO:
(4) Provide all Part Numbers (PNO) that satisfy the following condition: the supplier providing the part and the project using the part are in the same city.
- Join
Suppliers,Supply, andProjectstables: - Select tuples where
S.CITYequalsJ.CITY: - Project the
PNO:
(5) Provide the Project Names (JNAME) of all projects supplied by supplier S1.
- Select supply records for
S1: - Join with
Projectsto get project details: - Project
JNAME:
(6) Provide the Project Names (JNAME) of projects that use parts supplied by suppliers who supply ‘red’ parts. (Assuming “red parts” means parts with COLOR = 'Red', and “suppliers who supply red parts” means suppliers who supply at least one red part).
- Find
PNOof red parts: - Find
SNOof suppliers who supply these red parts: - Find
JNOof projects involved with these suppliers: - Join with
Projectsto getJNAME:
(7) Find the Project Names (JNAME) of projects that use all parts.
- Find all distinct
PNOfrom thePartstable: - Find all (
JNO,PNO) pairs fromSPJ: - Perform division to find
JNOof projects using all parts: - Join with
Projectsto getJNAME:
(8) Find the Supplier Names (SNAME) of suppliers who supply both parts P1 and P2.
- Find
SNOthat supplyP1: - Find
SNOthat supplyP2: - Intersect these sets of
SNO: - Join with
Suppliersto getSNAMEand project:
(9) Display the Part Names (PNAME) of parts that have the same color as the part named “TV”. (Assuming “TV” is a PNAME value).
- Find the
COLORof the part named “TV”: - Find
PNAMEof parts with thatCOLOR: - Project
PNAME(excluding the part ‘TV’ itself if required, but the query doesn’t specify exclusion):
(10) Find the Project Names (JNAME) of projects that use all parts supplied by S1.
- Find all distinct
PNOsupplied byS1: - Find all (
JNO,PNO) pairs fromSPJ: - Perform division to find
JNOof projects using all parts fromR_1: - Join with
Projectsto getJNAME:
Exercise6
Database Schema:
- Student: Student(Sno, Sname, Ssex, Sage, Sdept)
- Course: Course(Cno, Cname, Cpno) (Cpno is the Cno of the prerequisite course)
- SC (Student-Course): SC(Sno, Cno, Grade)
(1) Find the names (Sname) and ages (Sage) of all students in the ‘CS’ department.
(2) Find the student IDs (Sno) of all students who have a grade less than 60.
(3) Find the names (Sname) and departments (Sdept) of students who took course ‘C002’.
- Find
Snoof students who took ‘C002’: - Join with
Studentto get their names and departments:
(4) Find the student IDs (Sno) of those who took both course ‘C001’ and ‘C002’.
- Find
Snoof students who took ‘C001’: - Find
Snoof students who took ‘C002’: - Intersect the two sets of
Sno:
(5) Find the names (Sname) of students who took ‘C001’ but not ‘C002’.
- Find
Snoof students who took ‘C001’: - Find
Snoof students who took ‘C002’: - Find
Snoof students who took ‘C001’ but not ‘C002’: - Join with
Studentto get their names:
(6) Find students (Sno) who took all the courses taken by student ‘S001’.
- Find all
Cnotaken by student ‘S001’: - Use the
SCtable (projected toSno, Cno) andR_1in a division operation:
(7) Find the name (Cname) of the prerequisite course for ‘Data Structures’.
-
Find the
Cnoof ‘Data Structures’: -
Join
R_1withCourse(aliased to find the prerequisite): -
Project the
Cnameof the prerequisite course:
(8) For each course, find the number of students enrolled and the average grade.
(9) Find the student IDs (Sno) and average grades (AverageGrade) of students whose average grade is greater than 85.
- Calculate the average grade for each student:
- Select students whose
AverageGradeis greater than 85:
(10) Find the names (Sname) of students enrolled in more than 3 courses.
- Count the number of courses each student is enrolled in:
- Select students enrolled in more than 3 courses:
- Join with
Studentto get their names: