Multiple Nested Joins in SQL Query - mysql

I have a fairly simple database for a European style School system. A School can have multiple classes, Teachers can have assigned one or more classes from any School. Each student can have assigned a single class, and can have multiple grades from each teacher assigned to the class.
The checks for weather or not the teacher is assigned to the student class is done inside the software itself.
Here is the database diagram:
Database Diagram
I have to do get back the following reports using SQL:
Report Grades by Class: Select a class and have a table with every students grades, their average and the teacher who assigned the grade. (Table Sturcture: Teacher, Student, Grade_01, Grade_02, Grade_03, Grade_04, Average Grade)
Report Average Teacher Grade by School: Display a table with the teacher name, his class, and the average grade for the entire class. (Table Structure: Teacher, Class, Average Grade)
I managed to do the first "Report Grades by Class" Table by using the following SQL Code:
SELECT grades.grade_id, teachers.teacher_name, students.student_name, grades.grade_01, grades.grade_02, grades.grade_03, grades.grade_04
FROM grades
JOIN teachers
ON teachers.teacher_id = grades.teacher_id
JOIN students
ON students.student_id = grades.student_id
WHERE students.class_id = ?
But I don't know how to go about generating the second report, I have tried countless times...
So, how do I display a table with the teacher name, his class, and the average grade for the entire class?
Any help would be greatly appreciated.

select
teacher_name as 'Teacher',
class_name as 'Class',
avg(grade_01 + grade_02 + grade_03 + grade_04) as 'Average Grade' from teachers
join class_teacher on teachers.teacher_id = class_teacher.teacher_id
join clases on clases.class_id = class_teacher.class_id
join grades on grades.teacher_id = teachers.teacher_id
group by teacher_name, class_name

Thanks for your answer AnumR
I have modified the code you provided to make it so you can select the teachers and classes by the school ID.
But the code outputs the average by teacher and not by class.
SELECT teacher_name AS 'Teacher', class_name AS 'Class',
AVG(grade_01 + grade_02 + grade_03 + grade_04)/4 AS 'Average Grade' FROM teachers
JOIN class_teacher ON teachers.teacher_id = class_teacher.teacher_id
JOIN clases ON clases.class_id = class_teacher.class_id
JOIN grades ON grades.teacher_id = teachers.teacher_id
WHERE clases.school_id = 2
GROUP BY teacher_name, class_name

The fundamental problem here (and one I suspect you're reluctant to address) is one of poor design.
While by no means a definitive solution, a valid design might be as follows:
Teacher, Student, Grade, Score
Average grade would then be something calculated on the fly.

Related

How to design a simple database

I want to model a student, teacher, class relationship. Every student is associated with one teacher (the teacher can have many students). There are only three classes. The way I think of this is that there are three tables:
Student Table -> (student_id, student_name, class_id)
Teacher Table -> (student_id, student_name, class_id)
Class Table -> (class_id, class_name)
I'm not sure how to show the student-teacher relationship within the tables. How would we know which teacher is assigned to which student?
This can be accomplished with some simple joins.
Assuming that you want to find all the students associated with a certain teacher, you would start off by grabbing the row for the teacher. You would then join in the classes that the teacher teaches. Finally, you would join in the students that are in those classes.
This is known as a many-to-many relationship, and is an important concept in databases.
select
t.student_name, -- I suspect this col might actually be named teacher_name
s.student_name,
from
-- Find the classes that a teacher teaches
teacher_table t join class_table c on (t.class_id=c.class_id)
-- Find the students in those classes
join student_table s on (s.class_id=c.class_id)
where
t.student_id = ? -- Again, I suspect this should be "teacher_id"
This is a few more tables than you want, but several of the .NET examples that Microsoft has created revolve around a similar relational database.
Here is a link to that database:
https://msdn.microsoft.com/en-us/library/bb399731(v=vs.100).aspx
In this example, the student and the teacher are both kept in the person table and are related to the course table through two different Joining tables . . student grade and course instructor.
And here is the Contoso University Schema with link:
https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-a-more-complex-data-model-for-an-asp-net-mvc-application

Is my solution to this SQL query correct?

In my exam we were given the following relations:
COURSES(**Number**, School, CourseName)
STUDENTS(**SNumber**, Surname, FirstName, School)
EXAMS(**Student**, **Course**, Grade, Date)
where the keys are in bold. The EXAMS relation stores information of students that passed an exam for a given course .EXAMS.Student references STUDENTS.SNumber and EXAMS.Course references COURSES.Number.
We wear asked to write one SQL query that retrieves all the following information for each student number:
-their surname
-how many different exams they passed
-how many different grades they obtained
-the minimum, average and maximum grade they obtained in their exams."
Firstly, I included in my answer that I noticed that, as EXAMS only stores information about a student who passed an exam, there is no way to know if a student failed an exam and so we could only count how many different pass grades they obtained. Here is the query I wrote:
SELECT S.SNumber, S.Surame,
COUNT(E.Student) AS NumberOfExamsPassed,
COUNT(DISTINCT E.Grade) AS NumberOfDifferentPassGrades,
MIN(E.Grade) AS MinimumGrade,
MAX(E.Grade) AS MaximumGrade,
AVG(E.Grade) AS AverageGrade
FROM Students S, EXAMS E
GROUP BY E.Student;
Would this be a sufficient solution?
You should use Explicit Joins.
SELECT S.SNumber, S.Surame,
COUNT(E.Student) AS NumberOfExamsPassed,
COUNT(DISTINCT E.Grade) AS NumberOfDifferentPassGrades,
MIN(E.Grade) AS MinimumGrade,
MAX(E.Grade) AS MaximumGrade,
AVG(E.Grade) AS AverageGrade
FROM Students S
INNER JOIN EXAMS E ON S.SNumber = E.Student
GROUP BY E.Student;

mySQL Multiple Duplicate Handling (Dupes in Dupes)

So currently I'm fiddling with something that looks a little like below.
It's design is to display things from table attendance, if the student(student) has taken 3 or more instances of the same class (subject).
Sometimes teachers(teacher) have substitutes, so we need to know who was teaching when the student acquired the three classes. That is why we need it to display the teacher, as well as the subject & class of 3 or more instances of the same student taking the same class.
SELECT i.teacher, i.subject, i.student
FROM attendance i
INNER JOIN (
SELECT subject, student, COUNT(*)
FROM attendance
GROUP BY subject, student
HAVING COUNT(*) > 2) temp
ON temp.subject = i.subject
AND temp.student = i.student
ORDER BY subject, student
My dilemma is that I already got it to display 3 or more instances, and to display those instances... But I still need to compress it down so multiple instances of the same teacher, student, and subject aren't listed more than once and to be honest I've gotten as far as I can.
And finally a SQL Fiddle of what I'm left with, and trying to remove the duplicates in.
Help greatly appreciated!
Looks like you're close, you can either:
use SELECT DISTINCT .... or
add SELECT ..... FROM ... JOIN .... GROUP BY i.teacher, i.subject, i.student GROUP BY ...

Multiple SQL Join

I have to write a query that retrieves data from multiple tables, I have tried all my best to get it but keeps getting stuck.
I have the following tables:
Teacher:
teacher_code
initial
name
Student:
stud_no
initial
insertions
name
birth_date
address
city
class_code
Class:
class_code
classname
Module:
module_code
modulename
Teacher_module:
teacher_code
module_code
class_code
Grade:
stud_no
module_code
date
grade
And this is the query I need to write:
Show the names of the students with associated grades for the Databases examination of 21-11-1001.
I really appreciate your time.
I'm guessing "Databases" is a modulename.
I'm hoping 21-11-1001 is the grade.date, not some sort of code.
I don't know why you listed sql-server and mysql. I'm going to assume mysql, because I never get to use natural joins in real life. I'd be assuming any schema/references anyway, so I'll just let the engine figure it out.
select s.name, g.grade
from grades g
natural join student s
natural join module m
where m.modulename='Databases'
and g.date='1001-11-21'
there you go, grades from a thousand years ago.
Something like this?:
select s.name, g.grade
from student s
join grade g on s.stud_no = g.stud_no
join module m on m.module_code = g.module_code
where m.modulename = '21-11-1001'
It depends on which column contains 21-11-1001. If it is in the module table in the modulename column, then that should work.

MySQL Attendance System , Problems with joining tables, duplicate id's for 1 primary key

Ok So I am creating a Attendance System for a College and I am having trouble doing the tables in MySQL
The Problem I'm having is Grouping a group of students together for one class. So in MySQL
TABLE NAME: CourseGroup: courseGroup_id , student_id(FK), course_id(FK)
I want a number of students belonging to one class, this in hindsight will enable a teacher to undertake a register for that class group
In MySQL I have set the 'courseGroup_id as a unique field, however when I try to link 'courseGroup_id' in the Attendance table it only enables me to select 'student_id' and 'course_id'
Is it possible to select the courseGroup_id and display students for one class
My Attendance table looks like this:
Attendance: week_number, day, time, courseGroup_id, present
I want to be able to view all the students that belong to one class
I’m a bit lost with your terminology, you speak of “class id” but don’t reefer to that in your question – instead you use “course”.
I think the best option you can do here is create another table enabling a many to many relationship as many students can be registered to one or many courses. This type of table will enable a mapping between students and courses.
For example, if you create the mapping table “student_courses” with
student_id INT
course_id INT
You can then select students by course (joining the student table)
SELECT * from student_courses sc
INNER JOIN students s
ON s.student_id = sc.srudent_id
WHERE sc.course_id = ?CourseId
You can also reverse it and show the courses by for an individual course:
SELECT * from student_courses sc
INNER JOIN courses cs
ON cs.courset _id = sc.course_id
WHERE sc.student_id = ?StudentId
It is also worth pointing out that there should be two index on the student_courses, indexing both student_id and course_id for performance reasons.