IN / NOT IN and JOIN - sql

I have the following tables:
students (studentid, firstname, lastname)
finals (studentid, subjectid, finaldate, mark)
subjects (subjectid, subjectname, semester)
I need to know the students (bringing up the id) who took a database final exam. I've done the following:
select studentid
from finals
where subjectid in (select subjectid
from subjects
where subjectname = 'database');
Do I get the same result if I use a JOIN insted of IN?
select studentid
from finals f, subjects s
where f.subjectid = s.subjectid
and s.subjectname = 'database';
And what if I need to know the students (bringing up the id) who have never taken a database final?
Is it the same doing this...
select studentid
from finals
where subjectid not in (select subjectid
from subjects
where subjectname = 'database');
...Than this?
select studentid
from finals f, subjects s
where f.subjectid = s.subjectid
and s.subjectname <> 'database';
Thanks.

The answer to your first question is "yes" generally, but you should be using proper join syntax:
select studentid
from finals f join
subjects s
on f.subjectid = s.subjectid and s.subjectname = 'database';
The generally is because duplicates in the subjects table would appear in the join version but not the in version. The strict equivalent would be:
select studentid
from finals f join
(select distinct subjectid, subjectname
from subjects s
) s
on f.subjectid = s.subjectid and s.subjectname = 'database';
(A select distinct studentid comes close but it would eliminate duplicates in the finals table if it exists.)
The second answer is "no". The correct query is a left outer join with a where filter to only get the rows that do not match:
select studentid
from finals f left outer join
subjects s
on f.subjectid = s.subjectid and s.subjectname = 'database'
where s.subjectid is not null;

Related

How to extract rows from three tables

I know to ask this question is not appropriate.
Student table - ID, Name, GPA
Class table - ID, Title, Semester
Student_Class table - Student_ID, Class_ID, Student_Grade
From this table structure, how to extract the student name who attended class.title = ‘MATH101’ and class.semester = ‘FALL2018’.
Without much research I got to ask this question. How can I make a start on this?
Student_Class is join table which implements many-to-many relationship between Student and Class. So it just needed to join Student_Class with Student on student_id and Student_Class with Class on class_id.
select s.name
from Student s inner join Student_Class cs on s.id = cs.student_id
inner join Class c on cs.class_id = c.id
where c.title = ‘MATH101’ and c.semester = ‘FALL2018’.
You want to select the student name, so select from the student table. You only want to consider students who attended math in fall 2018, so add a where clause limiting the students accordingly.
This can achieved in various ways. One way to do this is
select name
from students
where id in
(
select student_id
from student_class
where class_id =
(
select id
from class
where title = 'MATH101'
and semester = 'FALL2018'
)
)
order by name;
Another is
select name
from students s
where exists
(
select null
from student_class sc
join class c on c.id = sc.class_id
where sc.student_id = s.id
and c.title = 'MATH101'
and c.semester = 'FALL2018'
)
order by name;

SQL Find student names according to grade

I am trying to print student names for each student that has more than one "2" grade. Grade is integer from CLASSSTUDENT table. Oracle database.
Code so far:
SELECT DISTINCT FIRSTNAME, LASTNAME
FROM PERSON
JOIN STUDENT ON PERSON.PERSONID = STUDENT.STUDENTID
JOIN CLASSSTUDENT ON STUDENT.STUDENTID = CLASSSTUDENT.STUDENTID
WHERE FINALGRADE = 2;
This get students having grade of "2". How must I change query to get students with more than one "2" grade?
SELECT FirstName, LastName
FROM Person p
INNER JOIN Student s ON p.PersonID = s.StudentID
INNER JOIN (
SELECT StudentID
FROM ClassStudent
WHERE FinalGrade = 2
GROUP BY StudentID
HAVING COUNT(*) > 1
) f ON f.StudentID = s.StudentID
or more simply:
SELECT FirstName, LastName
FROM Person p
INNER JOIN ClassStudent cs ON cs.StudentID = p.PersonID
WHERE cs.FinalGrade = 2
GROUP BY cs.StudentID, FirstName, LastName
HAVING COUNT(*) > 1
Though I prefer the former for reasons I don't myself fully understand (possibly something to do with only grouping on the primary key, or only using the group to filter the records... but really it just "feels" more right somehow).
I believe it would be something like:
SELECT FIRSTNAME, LASTNAME, COUNT(*)
FROM PERSON
JOIN STUDENT ON PERSON.PERSONID = STUDENT.STUDENTID
JOIN CLASSSTUDENT ON STUDENT.STUDENTID = CLASSSTUDENT.STUDENTID
WHERE FINALGRADE = 2
GROUP BY FIRSTNAME, LASTNAME
HAVING COUNT(*) >= 2;

Sql query to find everything about the students who are not registered in a particular class

Suppose I have three tables Student, Class, Student_Class(linking table).
Table:Student
Student_ID
FirstName
LastName
Table:Class
Class_ID
Class_name
Table:Student_Class (Linking Table)
StudentClass_ID
Class_ID
Student_ID
Given a particular Class_ID, I want to know everything about the students who are not registered for that particular class.
I tried the following but it does not work. Lets say I try for class id = 3
SELECT DISTINCT Student.*
FROM Student
INNER JOIN Student_Class
ON Student.Student_ID = Student_Class.Student_ID
WHERE ((NOT (Student_Class.Class_ID)= 3))
Flow
Match all student and all classes
Student INNER JOIN Student_Class ON (Student.Student_ID = Student_Class.Student_ID)
Reject Students in particular class (Example 3)
(Student_Class.Class_ID <> 3)
Query:
SELECT Student.*
FROM Student INNER JOIN Student_Class
ON (Student.Student_ID = Student_Class.Student_ID)
WHERE (Student_Class.Class_ID <> 3);
In order to get all Students that they are not in any Class, please try below:
SELECT Student.*
FROM
(
SELECT Student.*
, Student_Class.Class_ID
FROM Student LEFT JOIN Student_Class ON Student.Student_ID = Student_Class.Student_ID
WHERE ((Student_Class.Class_ID <> 3) OR (Student_Class.Class_ID IS NULL))
) Student LEFT JOIN Class ON Student.Class_ID = Class.Class_ID
;
Data:
Result:
Below query will show all student that did not attend 1 or more classes, including the class name.
SELECT Student.Student_ID, Student.FirstName, Student.LastName,
Class.Class_ID, Class.Class_name
FROM Class, Student
WHERE NOT EXISTS
(
SELECT *
FROM Student_Class
WHERE Student_Class.Student_ID = Student.Student_ID AND
Student_Class.Class_ID = Class.Class_ID
)

POSTGRESQL: how to filter to produce a query?

I have a text book question; List the ids and names of people who have received the grade an A for every class for the tables;
Student {studentID, name}
Grade {studentID, courseName, grade}
and I am not sure how to filter out the grades so that i only show the A students.
So far i have the solution
SELECT Student.studentID, Student.name
FROM Student, Grade
WHERE Student.studentID = Grade.StudentID AND
Grade.grade = 'A' AND
Grade.grade != 'B' AND
Grade.grade != 'C' AND
Grade.grade != 'D' AND
Grade.grade != 'F';
Is there a cleaner way I can filter this. It just seems a bit tedious that I write the not equals 4 times.
select studentid, s.name
from
student s
inner join
grade g using (studentid)
group by studentid, s.name
having bool_and(g.grade = 'A')
you can use NOT EXISTS class. we are getting all students which didn't get A and filtering them out.
SELECT DISTINCT Student.studentID, Student.name
FROM Student
JOIN Grade
ON Student.studentId = Grade.studentId
WHERE NOT EXISTS ( SELECT 1 FROM Grade G
WHERE G.grade !='A'
and G.studentID = Student.studentID
)

INNER JOIN to more than one table

I have four tables
student
-------
id, int
firstName, varchar
lastName, varchar
course
------
id, int
name, varchar
semester
--------
id, int
name, varchar
mark
----
studentId, int
courseId, int
semesterId, int
mark, int
I want to make a sql query that retrives firstName, lastName, courseName, semesterName and mark for every row in the mark table.
I tried to do it with INNER JOIN but I can't make INNER JOIN for more than one table.
That code I reached finally
select student.firstName, student.lastName, course.name, semester.name, mark.mark
from mark
INNER JOIN student ON student.id = mark.studentId
INNER JOIN course ON course.id = mark.courseId
INNER JOIN semester ON semester.id = mark.semesterId
In Ms Access you have to include parentheses in a query with multiple joins:
select st.firstName, st.lastName, c.name, sm.name, m.mark
from (((mark m
INNER JOIN student st ON st.id = m.studentId)
INNER JOIN course c ON c.id = m.courseId)
INNER JOIN semester sm ON sm.id = m.semesterId)
Try theta style join:
select student.firstName, student.lastName, course.name, semester.name, mark.mark
from mark, student ,course, semester
WHERE student.id = mark.studentId AND course.id = mark.courseId AND semester.id = mark.semesterId