SQL Find student names according to grade - sql

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;

Related

SQL query find records that not persists in other tables

I need to print all persons which are not students and not teachers. I have three tables. Oracle database. Code so far:
SELECT PersonID, FirstName, LastName, Gender, DateOfBirth
FROM PERSON
INNER JOIN STUDENT S ON PERSON.PersonID = S.StudentID
INNER JOIN TEACHER T ON PERSON.PersonID = T.TeacherID
WHERE PERSON.PersonID != S.StudentID
AND PERSON.PersonID != T.TeacherID;
I guess my query is wrong because it returns 0 results. Do you have any idea what must I change?
" my query is wrong because it returns 0 results"
Inner joins return records when there is a match. You're trying to find PERSON records which join to neither STUDENT nor TEACHER. So, change your query to use outer joins:
SELECT PersonID, FirstName, LastName, Gender, DateOfBirth
FROM PERSON
LEFT OUTER JOIN STUDENT S ON PERSON.PersonID = S.StudentID
LEFT OUTER JOIN TEACHER T ON PERSON.PersonID = T.TeacherID
WHERE S.StudentID is null
AND T.TeacherID is null;
This is an anti-join: it returns records from PERSON which don't match records in STUDENT and TEACHER.
Use not exists:
select p.*
from person p
where not exists (select 1 from teacher t where t.teacherid = p.personid) and
not exists (select 1 from students s where s.studentid = p.personid);
Although you can write this query with left join, I think the version using not exists is almost a direct translation of the question, making it easier to understand.
In Oracle, you can also write this using minus -- if you want only the id:
select personid
from person
minus
select teacherid
from teacher
minus
select studentid
from student;
--Try this with Left Outer Join...
SELECT
P.PersonID,
P.FirstName,
P.LastName,
P.Gender,
P.DateOfBirth
FROM PERSON P
LEFT OUTER JOIN STUDENT S ON P.PersonID = S.StudentID
LEFT OUTER JOIN TEACHER T ON P.PersonID = T.TeacherID
WHERE S.PersonID is null and T.PersonID is null

SQL find teacher courses query

I am trying to get teacher FIRSTNAME, LASTNAME and count of courses he got. Oracle database. CLASS table has columns: CLASSID, TEACHERID, CLASSNAME Current code:
SELECT DISTINCT FIRSTNAME, LASTNAME, COUNT(TEACHERID)
FROM PERSON
INNER JOIN TEACHER T ON PERSON.PERSONID = T.TEACHERID
INNER JOIN CLASS C ON T.TEACHERID = C.TEACHERID
WHERE T.TEACHERID = C.TEACHERID;
Where is my mistake?
Sounds like you need a GroupBy:
SELECT FIRSTNAME, LASTNAME, COUNT(T.TEACHERID)
FROM PERSON
INNER JOIN TEACHER T ON PERSON.PERSONID = T.TEACHERID
INNER JOIN CLASS C ON T.TEACHERID = C.TEACHERID
GROUP BY LASTNAME,FIRSTNAME
By the way, I initially deleted this answer because it's not a good way to do the grouping. I'd instead prefer grouping by TEACHERID, then joining back to get the names, rather than grouping by names.
I think this is a better approach:
SELECT FIRSTNAME, LASTNAME, C.NUMCLASSES
FROM PERSON
INNER JOIN TEACHER T ON PERSON.PERSONID = T.TEACHERID
INNER JOIN (SELECT TEACHERID, COUNT(CLASSID) AS NUMCLASSES FROM CLASS GROUP BY TEACHERID) C
ON C.TEACHERID=T.TEACHERID
you are missing the GROUP BY clause after the WHERE clause
GROUP BY FIRSTNAME, LASTNAME --all the selected columns except those in aggregate functions such as COUNT
May be you can try
SELECT FIRSTNAME, LASTNAME,
(select COUNT(C.TEACHERID) form CLASS C ON T.TEACHERID = C.TEACHERID)
as COURSECOUNT
FROM PERSON
INNER JOIN TEACHER T ON PERSON.PERSONID = T.TEACHERID

IN / NOT IN and JOIN

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;

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

How to get common category among columns in SQL

Consider the following schema for SQL:
Student (StudID, StudName, DeptID, Age, Gpa);
Course (CourseID, CourseName, InstructorID);
Department (DeptID, DeptName, Location);
Instructor (InstructorID, InstructorName, DeptID);
Section (SectionID, SectionName, Time, RoomID, CourseID, InstructorID);
Room (RoomID, RoomName, Location);
Enrolled (StudID, SectionID);
Q: How to find the names of all sections that either meet in common room or have five or more students enrolled?
Well I am not sure if it will work:)
Common names;
select st.StudName as names from Student as st inner join Departmant as d
on st.DeptID = d.DeptID inner join Instructor as i
on i.DeptID = d.DeptID inner join Course as c
on c.InstructorID = i.InstructorID inner join Section as s
on s.InstructorID = i.InstructorID inner join Room as r
on r.RoomID = s.RoomID inner join Enrolled as e
on e.StudID = st.StudID;
More than 5 student enrolled(Something experimental:);
select st.StudName as names from Student as st inner join Departmant as d
on st.DeptID = d.DeptID inner join Instructor as i
on i.DeptID = d.DeptID inner join Course as c
on c.InstructorID = i.InstructorID inner join Section as s
on s.InstructorID = i.InstructorID inner join Room as r
on r.RoomID = s.RoomID inner join Enrolled as e
on e.StudID = st.StudID where count(e.StudID = st.StudID)>4;
If you are using SQL-Server you can write the query like this(I didn't tested it. So I can't say it works 100% but I hope it gives you an idea):
SELECT SectionName
FROM Section
WHERE SectionID IN --Students in common room.
(
SELECT SectionID FROM Section
INNER JOIN Instructor ON Section.SectionID = Instructor.InstructorID --Section to which the Instructor belongs
INNER JOIN Department ON Department.DeptID = Instructor.DeptID --Department to which the Instructor belongs
INNER JOIN Room ON Room.Location = Department.Location --Room to which the Department belongs
)
OR --Student Enrollment greater than 5.
(
(SELECT COUNT(StudID) FROM Student
INNER JOIN Enrolled ON Student.StudID = Enrolled.StudID
INNER JOIN Section ON Section.SectionID = Enrolled.SectionID) >= 5
)
Q:6. Find the names of all sections that either meet in room New-8 or have five or more students enrolled.
Answer:
select sectionName
from student as S, Enrolled as E, Section as Se
where S.studId=E.studId AND E.sectionID=se.SectionID
group by sectionName
having count(*)>=3
UNION
SELECT sectionName
FROM SECTION S, ROOM R
WHERE S.RoomID=R.ROOMID AND R.RoomName='new2'
this is the correct query i have run it on Db