Is my solution to this SQL query correct? - mysql

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;

Related

Multiple Nested Joins in SQL Query

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.

MySQL Change column value to the least value in its category

Assuming only one school can be identified in a specific town, you are required to move students from duplicated schools to originally created schools. We also assume that lowest school id implies the first schools to be created in
the database, hence original schools.
I want to achieve this simply by changing the school ids for duplicate school+town to the smallest school id (the original) in that category. This will take care of the student records table that is linked to this one via foreign key (school id).
How would I go about doing this on the table attached? I'm thinking along the lines of SELECT MIN, CASE STATEMENTS as well as GROUP BY and COUNT() but I'm at a loss on how to combine these. Anyone have an idea/code on how I would achieve the requirement above?
I'd assume that the school id is a unique identifier (key). Therefore you can't just update it in the schools table. You'd rather need to update the school_id column in the students table to point to the original school's id.
If this is the case you can do something along the lines of
-- get all students and their current school info for update
UPDATE students st JOIN schools sc
ON st.school_id = sc.id JOIN (
-- get ids of original schools
SELECT town, name, MIN(id) id
FROM schools
GROUP BY town, name
) q -- join students with a list original schools ids
ON sc.town = q.town AND sc.name = q.name
-- change the school id to the original one
SET st.school_id = q.id
-- but only for students that were associated with non-original schools
WHERE st.school_id <> q.id
Here is dbfiddle demo

SQL keeping count of how many times

I have a table of grades/courses. I am trying to see how many times a person has taken a course, and also return the highest grade they have achieved.
So far I have:
SELECT tnumber, courseid, grade FROM grades
I need to display all tnumbers that have taken the same course more than once. Also list the students highest grade for the course.
How do you keep count of how many times a course has occurred?
I want to display the student's tnumber, course_id, attempts, and highest grade. And all within a single query.
If I need to show an example of my table/s. Let me know and Ill post them. I just don't want to overload the page with code!
Thanks.
For example (table alias G not necessary as only 1 table is involved using for example only)
SELECT g.tnumber, g.courseid, min(g.grade), count(*)
FROM grades g
GROUP BY g.tNumber, g.CourseID
This returns the tnumber and courseID for each record with the highest (alphabetic grade) and a count of how many records exist for that same tnumber and courseID. You could use count(*) or count(1).
Based on a prior posts I'm assuming grade is alphabetic.
SELECT tnumber, courseid, COUNT(courseid) times_taken, MAX(grade) highest_grade FROM grades GROUP BY tnumber, courseid
This assumes that grade is a number.
Try this query (I assume grade is a number column):
select tnumber, course_id, count(course_id), max(grade)
from grades
group by tnumber, course_id

MYSQL - Querying averages of ratings for multiple users in a single query

I am building a site one aspect of which involves teachers and rating teachers. Ratings are made by students, and when students are looking for teachers, among the criteria I'd like for them to be able to filter the teachers by include their average ratings.
Each rating by each student of each teacher puts the number of stars they rate the teacher into the database. I already have a query that can calculate the average stars for each teacher
SELECT AVG(star) AS Average FROM rating_table WHERE type = 'Member_review'
AND teacher_id = id_number
with id_number obviously being the user_id of the teacher.
When people are on the search page for all teachers, I'd love for them to be able to filter the teachers by rating, among other criteria. I can put this query in a foreach loop and have it run down each and every teacher id, but I suspect this will be a huge drag on the server - is there a way for me to put a string of comma-seperated ids into the query and have it find the average rating for each one? I did try this query and it did not work
SELECT AVG(star) AS Average FROM rating_table WHERE type = 'Member_review'
AND teacher_id IN(1,2,3, etc...)
Is there a way in which i can get the query to take the average for each teacher user_id and have it out put something like this?
Average Teacher ID
3.5 6
4.6 2
Yes. This is a basic aggregation query:
SELECT AVG(star) AS Average, teacher_id
FROM rating_table
WHERE type = 'Member_review' and
teacher_id IN(1,2,3, etc...)
group by teacher_id

Exercise Help - Select the register number of the students with the average highest score

I am studying SQL at my university, and I was practicing this exercise and got stuck! I have a database that stores all the exams passed by a student for a specific teach.
These are the tables in the database:
Student(**number**, name, birthday)
Exam(**student_number**, **teaching_code**, vote) *(store the exams passed by the students with vote)*
Teaching(**code**, name)
Where number is the primary key for the Student table, and code is for Teaching, "student_number" references "number" in Student, and "teaching_code" references "code" in Teaching.
The exercise asks to select the students’ numbers with the average highest score.
I know how to write a query which gives me a table containing the average for each students but I don't know how to select the highest from it or how to show the corresponding student number!
The solution with the limit command doesn't work if exists some students have the same highest average...
The query to show the average score per student is:
select avg(e.vote) as Average from STUDENT s, EXAM e
where s.number = e.student_number
group by s.number
EDIT:
I tried the MAX function in SQL, I have tried this:
select MAX( avg(e.vote) ) as Average from STUDENT s, EXAM e
where s.number = e.student_number
group by s.number
but it say "Error Code: 1111. Invalid use of group function"
Probably the solution is with a nested query but I can't realize it.
SELECT MAX(Expression)
FROM tables
WHERE Condition
You can check the documentation on how to use MAX and find highest value.
If you want to select the TOP 5 or 10 or 20... highest, use the TOP clause.
select student_code, MAX(avg_vote)
FROM (
SELECT student_code, AVG( vote) as avg_vote
FROM Exam
GROUP BY student_Code ) t
GROUP BY student_code
I didn't checked that query.
May query to select that max average is be like that
What a pity MySQL doesn't seem to support CTE's, then this would have been so simple.
select t.student_code, t.avg_vote
FROM (SELECT student_code, AVG(vote) as avg_vote
FROM Exam
GROUP BY student_Code) t
WHERE t.avg_vote = (select max(avg_vote)
FROM (SELECT student_code, AVG(vote) as avg_vote
FROM Exam
GROUP BY student_Code))
Continue studying hard, being presented with a likely answer is far less useful than actually reaching the conclusion yourself. Actually, if you're lucky, my proposal will not work (I haven't tested) so that you will have to come up with the right modification yourself!