Select students not having any corresponding course - sql

I have a simple problem but I want to use Not having. I have two tables: student_table, and student_course
STUDENT (
ID,
Name
)
STUDENT_COURSE (
ID,
student_ID,
course_ID
)
I want to select those student name that does not have any corresponding course_ID in the STUDENT_COURSE table, so I write
SELECT *
FROM STUDENT
LEFT JOIN STUDENT_COURSE ON STUDENT_COURSE.STUDENT_ID = STUDENT.ID
but how can I write Not having in the next?

To find STUDENT with no STUDENT_COURSE, you could use different methods. See this article for the comparisons:
using NOT EXISTS:
SELECT s.*
FROM STUDENT s
WHERE NOT EXISTS(
SELECT 1 FROM STUDENT_COURSE c WHERE c.STUDENT_ID = s.ID
)
using LEFT JOIN
SELECT
s.*
FROM STUDENT s
LEFT JOIN STUDENT_COURSE c
ON c.STUDENT_ID = s.ID
WHERE c.ID IS NULL
using NOT IN
SELECT *
FROM STUDENT
WHERE ID NOT IN(
SELECT STUDENT_ID FROM STUDENT_COURSE
)

Just Add [STUDENT_COURSE].[STUDENT_ID] IS NULL filter which will find the students not invloved in any course
Left Outer join will produce NULL values for the right table columns which don't have a match.
SELECT *
FROM [STUDENT]
LEFT JOIN [STUDENT_COURSE]
ON [STUDENT_COURSE].[STUDENT_ID] = STUDENT.ID
WHERE [STUDENT_COURSE].[STUDENT_ID] IS 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;

How to make a query from 4 tables

I am having a problem creating a View using SQL. I need to make a View of 4 tables:
tbl_school, tbl_teacher, tb_student, and tbl_class.
This is my table structure:
And this is my View Statement
SELECT
tbl_school.school_id,
tbl_school.school_nm,
(SELECT COUNT(*) FROM tbl_class) AS class,
(SELECT COUNT(*) FROM tbl_teacher) AS teacher,
(SELECT COUNT(*) FROM tbl_student) AS student
FROM
tbl_school
INNER JOIN tbl_teacher ON tbl_school.school_id = tbl_teacher.school_id
INNER JOIN tbl_class ON tbl_teacher.teacher_id = tbl_class.teacher_id AND tbl_school.school_id = tbl_class.school_id
INNER JOIN tbl_student ON tbl_class.class_id = tbl_student.class_id
GROUP BY
tbl_school.school_id
And this is the query result:
The problem is that I have one teacher in SD1 School and another teacher in SD2 School. Each teacher has one class and SD1 School has two students and SD2 School has one student.
Is there a way I can get the results that I desire?
You can use an aggregation containing DISTINCT keywords, and had better using aliasing and one more column (tbl_school.school_nm) within the GROUP BY list to make it a more proper SQL( Btw some DBMS don't allow excluding that column from GROUP BY while MySQL allows ) :
SELECT s.school_id, s.school_nm,
COUNT(DISTINCT c.class_id) AS class,
COUNT(DISTINCT t.teacher_id) AS teacher,
COUNT(DISTINCT d.student_id) AS student -- this is a presumedly existing column within the student table
FROM tbl_school s
JOIN tbl_teacher t ON s.school_id = t.school_id
JOIN tbl_class c ON t.teacher_id = c.teacher_id AND s.school_id = c.school_id
JOIN tbl_student d ON c.class_id = d.class_id
GROUP BY s.school_id, s.school_nm
Welcome to SO.
It has been a while since I have done this, but have you tried adding a WHERE modifier to your internal SQL select statements? Like this...
Side note: It makes more sense, to me, to also have a FK on tbl_student that links them to which school that they're in.
SELECT
tbl_school.school_id,
tbl_school.school_nm,
(SELECT COUNT(*) FROM tbl_class WHERE school_id=tbl_school.school_id) AS class,
(SELECT COUNT(*) FROM tbl_teacher WHERE school_id=tbl_school.school_id) AS teacher,
(SELECT COUNT(*) FROM tbl_student) AS student
FROM
tbl_school
INNER JOIN tbl_teacher ON tbl_school.school_id = tbl_teacher.school_id
INNER JOIN tbl_class ON tbl_teacher.teacher_id = tbl_class.teacher_id AND tbl_school.school_id = tbl_class.school_id
INNER JOIN tbl_student ON tbl_class.class_id = tbl_student.class_id
GROUP BY
tbl_school.school_id

SQL: Need to check columns for values that exist in another column

Using SQL, my job is to fetch the SSN of students who enrolled in a course without enrolling in that course’s prerequisite(s). I'm using Access. The tables I need are as follows:
STUDENT (SSN, SNAME, MAJOR, DOB, ADDRESS)
ENROLLED (SSN, CID, GRADE)
PREQ (CID, PREQCID, PASSINGGRADE, NOTE)
Here's what I've done so far.
select *
from
(select SSN, CID from ENROLLED) AS enrolled
left join
(select CID, PREQCID FROM PREQ) AS prereq ON enrolled.CID = prereq.CID;
What I'm missing is how to check each row of the same student on the condition WHERE enrolled.CID = prereq.CID for a PREQCID that's NOT in enrolled.CID.
Is what I'm asking for here a loop? Am I on the right track? Please keep in mind this I'm in an introductory course so the simplest of solutions is preferable.
Here's another way using not exists:
select e1.ssn
from enrolled e1 left join preq p on e1.cid = p.cid
where
p.preqcid is not null and
not exists (select 1 from enrolled e2 where e2.ssn = e1.ssn and e2.cid = p.preqcid)
This is essentially stating:
"Select the ssn for all enrollments where there is a prerequisite course and the prerequisite course ID does not exist in the table of enrollments for that ssn."
I use select 1 purely for optimisation - we don't care about the values held by the nested query, only whether or not the nested query returns one or more records.
You could also write this using joins as:
select e1.ssn
from
(
enrolled e1 left join preq p on e1.cid = p.cid
)
left join enrolled e2 on
p.preqcid = e2.cid and e1.ssn = e2.ssn
where
e2.cid is null
Here, the enrolled table is referenced twice: the first is left joined on the table of prerequisite courses for each course, and the second is left joined on the prerequisite course ID and the ssn from the original enrollment.
The where clause then causes records to be selected for which the link on the prerequisite course is null for the given ssn.
I'm sure there is a cleaner way to do this, but this gets you your result:
Select S.SSN, E.CID From Student S
Inner Join Enrolled E on E.SSN = S.SSN
Where E.CID IN (Select CID From PREQ Where Preqcid NOT IN
(Select CID From Enbrolled Where SSN = S.SSN))
This might work if analytic functions and CTEs are available:
with d as (
select ssn, cid,
count(distinct p.cid) over (partition by e.ssn, e.cid) ecnt, ,
count(distinct e.cid) over (partition by e.ssn, p.cid) pcnt
from enrolled e left outer join preq p on p.cid = e.cid
)
select distinct ssn, cid from d
where ecnt = pcnt;

What will be the query?

There are three tables
Student (STUDID, NAME, AGE, ADDRESS)
Course (COURSEID, COURSENAME, CREDIT)
Student_Course (SCID, STUDID, COURSEID)
How to show the total credits registered by one particular student id?
Here's the details about the tables
You should use JOIN , SUM() and group by
select a.STUDID, a.NAME, sum(b.CREDIT)
from Student a
inner join Student_Course c on a.STUDID = c.STUDID
inner join Course b on c.COURSEID = b.COURSEID
group by a.STUDID, a.NAME

Selecting exact value in SQL

I am stuck on a query and decided to ask for help here.
I have 2 tables Students and Values. In students I have the Name and in Values I have the grade.
Let's suppose we have 3 students.
**X** 7,8,10
**Y** 6,9,7
**Z** 7
How can i select the students with the grade EXACTLY "7"?
I tried:
SELECT WHERE grade = 7 But it takes in the consideration the students who have "7" but also other grades too.
I think this problem is tricky, can someone give a hint?
One way is to use a comparison between unconditional and conditional counts:
select s.student_name
from students s join grades g on s.student_id = g.student_id
group by student_id
having count(*) = count(case when g.value = 7 then 1 end)
;
(guessing at some column names along the way)
How it works: After joining the two tables, the rows are grouped by student_id. Then COUNT(*) counts all the grades, and the conditional count counts the grades equal to 7. The query returns the student names when the two counts are equal (meaning all the grades are 7).
Another solution (less efficient):
select s.student_name
from students s inner join grades g on s.student_id = g.student_id
where g.grade = 7
minus
select s.student_name
from students s inner join grades g on s.student_id = g.student_id
where g.grade != 7 or g.grade is null
;
One simple way is to look at the task like this: Find students that have no grade other than seven.
select *
from students
where not exist
(
select *
from grades
where grades.student_id = students.student_id
and grades.grade <> 7
);
or
select *
from students
where student_id not in
(
select student_id
from grades
where grade <> 7
);
I think that an INNER JOIN followed by an exclusive LEFT JOIN would do the trick. Something like this:
WITH
seven AS (
SELECT a.id, a.name, b.grade
FROM student_name a
INNER JOIN student_grade b
ON a.id = b.id
WHERE b.grade = '7'
)
, not_seven AS (
SELECT a.id, a.name, a.grade
FROM seven a
LEFT JOIN student_grade
ON a.id = b.id
WHERE b.id IS NULL
AND b.grade <> '7'
)
SELECT * FROM not_seven;
what about using count and sum? Would that work?
select s.student, Count(v.grade), sum(v.grade)
From student as s
join values as v on v.student = s.student
group by student
having sum(v.grade) = 7 and count(v.grade) = 1