SQL SELECT using a "join table" - mysql

Table Student maps Student.student_name to Student.student_id
Table Course maps Course.course_name to Course.course_id
Table Enrollment maps Enrollment.student_id to Enrollment.course_id (I've heard this referred to as a join table.)
What is the SELECT statement that, given a student name, will return his list of course names? I think this may be some of it:
SELECT c.course_name FROM Course c
INNER JOIN Enrollment e ON c.course_id = e.course_id
...
WHERE s.student_name = 'Tom';
Beyond that, I'm clueless.
(This isn't homework, it's just a simplification of a work problem.)

SELECT c.course_name FROM Enrollment e
INNER JOIN Course c ON c.course_id = e.course_id
INNER JOIN Student s ON s.student_id = e.student_id
WHERE s.student_name = 'Tom';
also
SELECT c.course_name
FROM Enrollment e, Course c, Student s
WHERE c.course_id = e.course_id
AND s.student_id = e.student_id
AND s.student_name = 'Tom';

Related

Given the following schema, what would be the query to print all students in a teachers class?

Schema:
This is what I'm thinking, but I don't think its right:
SELECT distinct t.teacherid, s.fname
FROM tea_cou t, students s, stu_cou c
WHERE t.courseid = c.courseid
You have to join the tables and then filter by teacher name.
SELECT S.*
FROM Teachers T
INNER JOIN Tea_Cou TC ON Tc.TeacherId = T.TeacherId
INNER JOIN Courses C ON C.CourseId= TC.CourseId
INNER JOIN Stu_Cou SC ON SC.CourseId = C.CourseId
INNER JOIN Students S ON S.StudentId = SC.StudentId
WHERE T.LNAME= 'name'

How to refer without foreign key?

Create two tables:
Course(Course_id(primary key), Course_name)
Student(Roll_no(primary key), Name,Course_id(Foreign key)) and Retrieve the names of all the students who are admitted in the course 'BSC'.
let, the course_id for BSC be 105.
For which the query will be:
SELECT Name FROM Student WHERE Course_id = 105
Can I query for the name of the student without knowing the Course_id (just using the Course_name) ?
You could use an inner join between the tables
SELECT s.Name
FROM Student s
INNER JOIN Course c on c.course_id = s.Course_id
WHERE c.Course_name = 'your_course_name'
or using like
SELECT s.Name
FROM Student s
INNER JOIN Course c on c.course_id = s.Course_id
WHERE c.Course_name like 'your_course_name'
Or use WHERE IN (...)
SELECT
Student.Name
FROM
Student
WHERE
Student.Course_id IN (
SELECT
Course.cource_id
FROM
Course
WHERE
Course.Name = 'BSC'
)
Yes, you can.
SELECT st.Name
FROM Student st
INNER JOIN Course c on c.course_id = st.Course_id
WHERE
c.Course_name = 'Course_Name';

Is this the right way to join tables to fetch data?

I have a database with the tables:
Student(SID,Name,Surname,Age)
Registration(StudentID,CourseID)
Course(CID,Name,Cost)
I would like to extract only the name of the courses with students younger than 20. Will the query below do just that?
SELECT C.NAME
FROM Course C
INNER JOIN Registration
INNER JOIN Student S
WHERE CID = CourseID
AND SID = StudentID
AND Age < 20
GROUP BY C.NAME
I would also like to extract the number of students in each course having students younger than 20. Is it correct to do it as below?
SELECT count(S.NAME)
,C.NAME
FROM Student S
INNER JOIN Course C
INNER JOIN Registration
WHERE Age < 20
AND CID = CourseID
AND SID = StudentID
GROUP BY C.NAME
You are missing the ON part for the join otherwise it would just be a CROSS JOIN.
Your first query should look like this if you want just a distinct list of student names:
SELECT DISTINCT C.NAME
FROM Course C
INNER JOIN Registration R ON C.CID = R.CourseID
INNER JOIN Student S ON R.StudentID = S.SID
WHERE Age < 20
Your second query shouldn't really have the C.Name in the select if you want to get just a count unless you want a count of how many students have that name.
SELECT count(*)
FROM Student S
INNER JOIN Registration R ON s.SID = R.StudentID
INNER JOIN Course C ON c.CID = R.CourseID
WHERE Age < 20
GROUP BY C.NAME
First join these tables, then group by Course's PK(CID), Add the HAVING condition to filter the course which has students younger than 20.
Then use Course table to join the result to get the course name and count of students in the course.
SELECT
T1.Name,
T2.StudentCount
FROM
Course T1
INNER JOIN (
SELECT
c.CID,
COUNT(s.SID) AS StudentCount
FROM
Course c
LEFT JOIN Registration r ON c.CID = r.CourseID
LEFT JOIN Student s ON s.SID = r.StudentID
GROUP BY c.CID
HAVING COUNT(IF(s.Age < 20, 1, NULL)) > 0
) T2 ON T1.CID = T2.CID
More correctly, you should move the conditions of the join, to the join statements themselves by including them in the on clause instead of the where. While the results may not change in this instance, if you were to start including outer joins you would encounter difficulties.
SELECT count(S.NAME)
,C.NAME
FROM Student S
INNER JOIN Registration R
ON s.SID = R.StudentID
INNER JOIN Course C
ON c.CID = R.CourseID
WHERE Age < 20
GROUP BY C.NAME
There's a fiddle here showing it in action: http://sqlfiddle.com/#!9/c3b8f/1
Your first query will also produce the results you want, but again, you should move the join predicates to the join itself. Also, you don't need to perform the grouping just to get distinct values, mysql has an expression for that called distinct. So rewritten, the first query would look like:
SELECT DISTINCT C.NAME
FROM Student S
INNER JOIN Registration R
ON s.SID = R.StudentID
INNER JOIN Course C
ON c.CID = R.CourseID
WHERE Age < 20.
Again, the results are the same as what you have already but it is easier to 'read' and will put you in good stead when you move on to other queries. As it stands you have mixed implicit and explicit join syntax.
This fiddle demonstrates both queries: http://sqlfiddle.com/#!9/c3b8f/4
edit
I may have misinterpreted your original question - if you want the total number of students enrolled in a course with at least one student under 19, you can use a query like this:
select name, count(*)
from course c
inner join registration r
on c.cid = r.courseid
where exists (
select 1
from course cc
inner join registration r
on cc.cid = r.courseid
inner join student s
on s.sid = r.studentid
where cc.cid = c.cid
group by cc.cid
having min(s.age) < 20
)
group by name;
Again with the updated fiddle here: http://sqlfiddle.com/#!9/c3b8f/17

How do i write this SQL query for an ALL condition?

I need to build an SQL query in MySQL to solve a problem as part of an assignment for class. I've been working at this problem for awhile, but I'm having a hard time figuring out how to structure this query properly. I'm rather new to the SQL language and databases in general and I'm stumped on this question. I have posted what I've come up with so far, but unfortunately I have not been able to get the results I'm looking for. If anyone could give me some guidance on how to accomplish this I would greatly appreciate it.
Here's what my table structure looks like:
course(cid, fid, room)
enroll(cid, sid, grade)
faculty(fid, fname, dept, rank)
student(sid, sname, major, credits)
Here's the query I need to build:
Show the faculty id and faculty name for all faculty that have taught all computer science majors (major = 'CSC').
Here's what I've tried so far:
select f.fid, f.fname
from faculty f
join course c
on f.fid = c.fid
join enroll e
on c.cid = e.cid
join student s
on e.sid = s.sid
where s.sid = ALL
(select sid
from student
where major = 'CSC');
select f.fid, f.fname
from faculty f
join course c
on f.fid = c.fid
join enroll e
on c.cid = e.cid
join student s
on e.sid = s.sid
group by f.fid, s.sid
having s.sid = ALL
(select sid
from student
where major = 'CSC'));
The logical hurdle I'm having a hard time understanding is how to make sure that the faculty member is teaching ALL of the current CSC majors. You can see that I've tried to add some logic to check each record returned, but I'm afraid I may be misunderstanding the syntax. These queries will run, but they return empty sets. Thanks for the help.
I agree the question may be unclear, and they might just be after all faculty that have taught any CSC major. However, just in case you still need all the faculty that have taught all CSC major, this should work:
The following query tells us the pairs of faculty and CSC majors:
select f.fid, s.sid
from faculty f
inner join course c
on f.fid = c.fid
inner join enroll e
on e.cid = c.cid
inner join student s
on e.sid = s.sid
where s.major = 'CSC'
group by f.fid, s.sid
Therefore, if we know the count of students who are computer science majors:
select count(1)
from student s
where s.major = 'CSC'
Then we can add up the number of CSC majors taught by each faculty member, and check it's equal to the total number of CSC majors:
select b.fid, b.fname
from (
select a.fid, a.fname, count(1) as taught_count
from (
select f.fid, f.fname, s.sid
from faculty f
inner join course c
on f.fid = c.fid
inner join enroll e
on e.cid = c.cid
inner join student s
on e.sid = s.sid
where s.major = 'CSC'
group by f.fid, s.sid
) a
group by a.fid, a.fname
) b
where b.taught_count = (
select count(1)
from student s
where s.major = 'CSC'
)
What you've done looks pretty good. I think you may just be over thinking it. This should logically give you what you're looking for:
Select f.fid, f.fname
from faculty f
join course c on c.fid = f.fid
join enroll e on e.cid = c.cid
join student s on s.sid = e.sid
Where major = 'CSC'
group by f.fid, f.fname
Try with
select f.fid, f.fname
from faculty f
join course c
on f.fid = c.fid
join enroll e
on c.cid = e.cid
join student s
on e.sid = s.sid
where s.sid IN (select sid from student where major = 'CSC');

How to triple join tables to find and find entries that match two things?

I have a simple problem that's hard to describe (at least for me).
Consider the following schema for a database modeling courses:
COURSE (cid, did, name, num, creditHours),
STUDENT (sid, fname, lname, did)
ENROLLED_IN (eid, sid, cid)
What is a query that will find the sid of the students enrolled in course.name=Math" and "Science"?
I'm sorry i asked a similar (simpler) question thinking I could figure the rest out but I could not: https://stackoverflow.com/questions/18902489/how-to-find-entries-in-database-that-meet-multiple-matches
AS the other page suggests, you need to do two JOIN's to the same table. But since you want to use the Name and not the cid, you join to the COURSE based on the enrollment data.
SELECT DISTINCT s.sid
FROM STUDENT s
INNER JOIN ENROLLED_IN e ON e.sid = s.sid
INNER JOIN COURSE c ON c.cid = e.cid AND c.Name = 'Math'
INNER JOIN COURSE c2 ON c2.cid = e.cid AND c2.Name = 'Science'
If you need the whole student record, then...
SELECT STUDENT.*
FROM STUDENT
INNER JOIN
(SELECT DISTINCT s.sid
FROM STUDENT s
INNER JOIN ENROLLED_IN e ON e.sid = s.sid
INNER JOIN COURSE c ON c.cid = e.cid AND c.Name = 'Math'
INNER JOIN COURSE c2 ON c2.cid = e.cid AND c2.Name = 'Science'
) t0 ON t0.sid = STUDENT.sid
EDIT Instead of DISTINCT you could also use GROUP BY, ala
SELECT s.sid
FROM STUDENT s
INNER JOIN ENROLLED_IN e ON e.sid = s.sid
INNER JOIN COURSE c ON c.cid = e.cid AND c.Name = 'Math'
INNER JOIN COURSE c2 ON c2.cid = e.cid AND c2.Name = 'Science'
GROUP BY s.sid
EDIT and instead of using two joins, you can use HAVING clauses
SELECT s.sid
FROM STUDENT s
INNER JOIN ENROLLED_IN e ON e.sid = s.sid
INNER JOIN COURSE c ON c.cid = e.cid
WHERE c.Name IN ('Math', 'Science')
GROUP BY s.sid
HAVING COUNT(*) = 2