Multiple SQL Join - mysql

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.

Related

mySQL: how to go along 3 different tables, referring to different column in each table but using primary keys

I'm trying to find out which schools had students that did not complete their exams in 2018. So I've got 3 tables set up being: ExamInfo, ExamEntry and Students. I'm going to try use the ExamInfo table to get information from the Students table though, I obviously only want the student information that did not complete their exam in 2018. Note: I'm looking for students that attended, though did not complete the exam, with this particular exam you can look at completed exam as passed exam.
Within ExamInfo I have the columns:
ExamInfo_Date --when exam took place, using to get year() condition
ExamInfo_ExamNo --unique student exam ID used to connect with other tables
ExamInfo_Completed --1 if completed, 0 if not.
...
Within ExamEntry I have the related columns:
ExamEntry_ExamNo --connected to ExamInfo table
ExamEntry_StudentId --unique studentId used to connect to Students table
ExamEntry_Date -- this is same as ExamInfo_Date if any relevance.
...
Within Students I have following columns:
Students_Id --this is related to ExamEntry_StudentId, PRIMARY KEY
Students_School --this is the school of which I wish to be my output.
...
I want my output to simply be a list of all schools that had students that did not complete their exams in 2018. Though my issue is with getting from the ExamInfo table, to finding the schools of which students did not complete their exam.
So far I've:
SELECT a.Students_School, YEAR(l.ExamInfo_Date), l.ExamInfo_Completed
FROM ExamInfo l ??JOIN?? Students a
WHERE YEAR(l.ExamInfo_Date) = 2018
AND l.ExamInfo_Completed = 0
;
I'm not even sure if going through the ExamEntry table is necessary. I'm sure I'm meant to use a join, though unsure of how to appropriately use it. Also, with my 3 different SELECT columns, I only wish for Students_School column to be output:
Students_School
---------------
Applederry
Barnet Boys
...
Clearly, you need a JOIN -- two in fact. Your table has exams, students, and a junction/association table that represents the many-to-many relationship between these entities.
So, I would expect the FROM clause to look like:
FROM ExamInfo e JOIN
ExamEntry ee
ON ee.ExamEntry_ExamNo = e.ExamNo JOIN
Students s
ON ee.ExamEntry_StudentId = s.Students_Id

Have to enter mySQL criteria twice?

Say I have two tables:
Table: customers
Fields: customer_id, first_name, last_name
Table: customer_cars
Fields: car_id, customer_id, car_brand, car_active
Say I am trying to write a query that shows all customers with a first name of "Karl," and the brands of the ** active ** cars they have. Not all customers will have an active car. Some cars are active, some are inactive.
Please keep in mind that this is a representative example that I just made up, for sake of clarity and simplicity. Please don't reply with questions about why we would do it this way, that I could use table aliases, how it's possible to have an inactive car, or that my field names could be better written. It's a fake example that is intended be very simple in order to illustrate the point. It has a structure and issue that I encounter all the time.
It seems like this would be best done with a LEFT JOIN and subquery.
SELECT
customer_id,
first_name,
last_name,
car_brand
FROM
customers
LEFT JOIN
(SELECT
customer_id,
car_brand
FROM
customer_cars
INNER JOIN customers ON customer_cars.customer_id = customers.customer_id
WHERE
first_name = 'Karl' AND
customer_cars.car_active = '1') car_query ON customers.customer_id = car_query.customer_id
WHERE
first_name = 'Karl'
The results might look like this:
first_name last_name car_brand
Karl Johnson Dodge
Karl Johnson Jeep
Karl Smith NULL
Karl Davis Chrysler
Notice the duplication of 'Karl' in both WHERE clauses, and the INNER JOIN in the subquery that is the same table in the outer query. My understanding of mySQL is that this duplication is necessary because it processes the subquery first before processing the outer query. Therefore, the subquery must be properly limited so it doesn't scan all records, then it tries to match on the resulting records.
I am aware that removing the car_active = '1' condition would change things, but this is a requirement.
I am wondering if a query like this can be done in a different way that only causes the criteria and joins to be entered once. Is there a recommended way to prioritize the outer query first, then match to the inner one?
I am aware that two different queries could be written (find all records with Karl, then do another that finds matching cars). However, this would cause multiple connections to the database (one for every record returned) and would be very taxing and inefficient.
I am also aware of correlating subqueries, but from my understanding and experience, this is for returning one field per customer (e.g., an aggregate field such as how much money Karl spent) within the fieldset. I am looking for a similar approach as this, but where one customer could be matched to multiple other records like in the sample output above.
In your response, if you have a recommended query structure that solves this problem, it would be really helpful if you could write a clear example instead of just describing it. I really appreciate your time!
First, is a simple and straight query not enough?
Say I am trying to write a query that shows all customers with a first
name of "Karl," and the brands of the ** active ** cars they have. Not
all customers will have an active car. Some cars are active, some are
inactive.
Following this requirement, I can just do something like:
SELECT C.first_name
, C.last_name
, CC.car_brand
FROM customers C
LEFT JOIN cutomer_cars CC ON CC.customer_id = C.customer_id
AND car_active = 1
WHERE C.first_name = 'Karl'
Take a look at the SQL Fiddle sample.

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 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.

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!