SQL- Find the students who are missing their grades in database - sql

I have three tables in my database. the first one is students which has student_id as primary key. the second one is courses table which has course_id as primary key and at last I have a grades table which has id_student and id_course as foreign keys, and a grade field. I want to the get details of students, who are missing their grades in grades table.
I've searched on stack overflow but could not find the exact answer i am looking for. and what i have tried so far is this following query:
select st.student_id,
st.lname,
st.fname,
cs.course_id,
g.grade
from students st
join grades g
on g.id_student = st.student_id
join courses cs
on cs.course_id = g.id_course
where g.grade is null
If I try this same query without where condition i get 39 rows but i should get 40 because in my database there is one student who is missing grades in course_id 20.
** the missing thing is student_id, where course_id is 20 and grade doesnt exist for it.**

I think the join on grades requires two keys. If I assume that students should be taking all courses, then this would look like:
select st.student_id, st.lname, st.fname, cs.course_id,
g.grade
from students st cross join
courses c left join
grades g
on g.id_student = st.student_id and
g.id_course = c.course_id
where g.grade is null;
The CROSS JOIN generates all combinations of students and courses. The LEFT JOIN/WHERE filters out the ones with missing grades.

Because you use JOIN you are only getting the rows that exist in all 3 tables.
If you change the JOINS to LEFT OUTER JOIN you will see NULLS for the student without a grade.
See https://www.w3schools.com/sql/sql_join.asp
and many other links on the web
SELECT * FROM
(
select st.student_id,st.lname,st.fname,cs.course_id,g.grade
from students st
LEFT OUTER join grades g on g.id_student = st.student_id
LEFT OUTER join courses cs on cs.course_id = g.id_course
)SUB_Q WHERE SUB_Q.grade IS NULL
The inner query should return all students and the ones without a grade should have a grade of null in that. So the WHERE clause of the outer query should filter down to just those.

The join function for the grades table is only looking for results that match both the grades table and students table. Try a full outer join here to include all fields regardless of if they match on both tables. See code below:
SELECT
st.student_id, st.lname, st.fname, cs.course_id, g.grade
FROM students st
FULL OUTER JOIN grades g
ON g.id_student = st.student_id
FULL OUTER JOIN courses cs
ON cs.course_ID = g.id_course
WHERE g.grade IS NULL

Related

Getting data for each Student from other tables

I am trying to get information for each student in a database. I know that there are exactly 4 students and that between all students, there are 6 enrollments (ie. some students are enrolled in multiple courses). Therefore, the proper output would have 6 rows, all containing the necessary student info. There would be duplicate students in the returned query. I am able to join the students and the enrollments just fine and end up with the 6 total enrollments. However, once I join in the other tables to get data about the courses that the students are enrolled in, I end up getting more and more rows. Depending on how I format my query, I get between 7-11 rows. All that I want is the 6 rows that correspond to the enrollments and nothing more. Why does that happen like this and how do I fix it?
I have tried different kinds of joins, unions, intersections, and have been working at the question for well over an hour. This is what I have currently:
Select s.sid, e.term, c.cno, e.secno, ca.ctitle
from Students as s
join Enrolls as e
on s.sid = e.sid
join Courses as c
on e.secno = c.secno
join Catalogue as ca
on ca.cno = c.cno
question details
database details
It looks like the Courses and Enrollment tables have what we call 'a composite key'. I bet you must join the c and e tables with both term and secno columns.
Your query mus be like this:
SELECT s.sid, e.term, c.cno, e.secno, ca.ctitle
FROM Students AS s
JOIN Enrolls AS e ON s.sid = e.sid
JOIN Courses AS c ON e.secno = c.secno AND e.term = c.term
JOIN Catalogue AS ca ON ca.cno = c.cno
When you have a composite key and uses only one of the columns to join, you will get unwanted rows from the foreign table, making a Cartesian product result

Finding out zero frequency values from a column with inner join

I have two tables named courses and teachers. I need to find the list of teachers who don't take any courses.
This is the query I wrote for getting the teacher who took the most numbered courses -
SELECT t.name AS teacher_name
, COUNT(c.teacher_id) AS courses_taken
FROM courses c
JOIN teachers t
ON c.teacher_id = t.id
GROUP
BY c.teacher_id
ORDER
BY courses_taken DESC
LIMIT 1;
By reversing this query I am getting the teacher's list who take minimum numbers of courses which is 1 but I need to find the list of teacher who don't take any courses.
Left Join and Where condition can help you.
SELECT *
FROM teachers t
LEFT
JOIN courses c
ON t.id = c.teacher_id
WHERE c.teacher_id IS NULL
Teachers don't usually "take" courses. They "teach" courses. Students "take" courses.
That said, not exists seems appropriate:
SELECT t.*
FROM teachers t
WHERE NOT EXISTS (SELECT 1
FROM courses c
WHERE c.teacher_id = t.id
);
If you think about this, it is almost a direct translation of your question: Get teachers where there is no course that the teacher teachers.

What Join to use against 2 Tables for All Data

Hi I am looking to find out what join I would use if I wanted to join 2 tables together. I currently have a list of all students so 25 students to 1 class and the other table only shows 7 of those names with their test results.
What I would like is to have 1:1 join for the ones with the test results and the other ones without I would like to show them underneath so all in all I have 20 records.
If somebody could please advise on how I could achieve this please.
Thanks in advance.
It sounds like you want an OUTER JOIN.
For this example, we'll assume that there is a table named student and that it contains a column named id which is UNIQUE (or PRIMARY) KEY.
We'll also assume that there is another table named test_result which contains a column named student_id, and that column is a foreign key referencing the id column in student.
For demonstration purposes, we'll just make up some names for the other columns that might appear in these tables, name and score.
SELECT s.id
, s.name
, r.score
FROM student s
LEFT
JOIN test_result r
ON r.student_id = s.id
ORDER
BY r.student_id IS NULL
, s.score DESC
, s.id
Note that if student_id is not unique in test_result, there is potential to return multiple rows that match a row in student.
To get (at most) one row returned from test_result per student, we could use an inline view.
SELECT s.id
, s.name
, r.score
FROM student s
LEFT
JOIN ( SELECT t.student_id
, MAX(t.score) AS score
FROM test_result t
GROUP BY t.student_id
) r
ON r.student_id = s.id
ORDER
BY r.student_id IS NULL
, s.score DESC
, s.id
The expressions in the ORDER BY clause are designed to return the students that have matching row(s) in test_result first, followed by students that don't.
This is just a demonstration, and very likely excludes some important criteria, such as which test a score should be returned for. But without a sample schema and some example data, we're just guessing.
You are looking for a left outer join or a full outer join.
The left outer join will show all students and their tests if they have them.
select *
from Students as s
left outer join Tests as t
on s.StudentId = t.StudentId
The full outer join will show all students with their tests if they have them, and tests even if they do not have students.
select *
from Students as s
full outer join Tests as t
on s.StudentId = t.StudentId

In PostgreSQL how do you join two tables select separate information

Having trouble with joins.
I have a table called subjects
subno subname
30006 Math
31445 Science
31567 Business
I also have a another table called enrollment
subno sno
30009 980008
4134 988880
etc..
how to list subject numbers and subject names for student 9800007 ?
If you want to return zero rows for students without an enrolment, use a LEFT [OUTER] JOIN, eg:
SELECT e.sno, s.subno, s.subname
FROM enrollment e LEFT OUTER JOIN subjects s ON s.subno = e.subno
WHERE e.sno=988880;
To return no rows for students without enrolments, use an INNER JOIN:
SELECT e.sno, s.subno, s.subname
FROM enrollment e INNER JOIN subjects s ON s.subno = e.subno
WHERE e.sno=988880;
Note that join order is important for outer joins (RIGHT [OUTER] JOIN and LEFT [OUTER] JOIN - the OUTER keyword is optional) but not for INNER JOIN. For that reason, #swetha's answer has a problem: the join order is reversed if you're looking for information about a student.
See this SQLFiddle
Try this
select *
from subjects s
left join enrollment e on s.subno = e.subno
where sno=9800007

SQL Join Retrieves more rows than expected

Suppose I have the following tables
Students (StudentId int Pk, StudentName nvarchar)
Lectures (LectureId Pk, StartDate, EndDate)
Enrollment (StudentID, LectureID)
When I execute the following query:
select StudentID From Students
I get 8 rows..
And when i execute:
select S.StudentID From Students S join Enrollment En On S.StudentID = En.StudentID
I get 11 Rows
Why is that, and how to use join without retrieving extra rows?
Your join is fine.
This means that there is more than one Enrollment per Student - e.g. Students have enrolled in more than one lecture / series of lectures
Assuming that a student can only register for one lecture at a time, then you will also need to join to lecture and use the date fields
Also, if a student is not currently enrolled in anything, you will need to consider a left outer join.
So your query might then look like
SELECT S.StudentID FROM Students S
LEFT OUTER JOIN Enrollment En On S.StudentID = En.StudentID
INNER JOIN Lectures l ON en.LectureId = l.Lecture ID
WHERE getdate() BETWEEN l.StartDate and l.EndDate
But you would need to have rules in place to ensure that the student cannot concurrently register for more than one lecture (if that is indeed what you expected)
HTH
Use a LEFT JOIN
EDIT: nevermind, it is as said below/above/whatever. You must have students with multiple lectures/enrollments. You will need to group by student to get 8 rows again.
select S.StudentID From Students S
join Enrollment En On S.StudentID = En.StudentID
group by S.StudentID