How to extract rows from three tables - sql

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;

Related

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 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
)

SQL not group by expression, Find student who has taken at least 5 courses

select s.name, s.id
from student s join takes t on t.id = s.id
where s.name like 'D%'
group by s.name, s.id
having (
select count(distinct c.course_id)
from course c
where c.dept_name = 'History' and c.course_id = t.course_id)>4
order by s.name
I am confused about how GROUP BY works. I am trying to find the students who has taken at least 5 courses from history department and name start with D.
Not sure with the nested subqueries...
course(course id, title, dept name, credits)
student(ID, name, dept name, tot_cred)
takes(ID, course_id, sec_id, semester, year, grade)
You have to additionally JOIN with course table:
select s.name, s.id
from student s
inner join takes t on t.id = s.id
inner join course c on c.course_id = t.course_id
where s.name like 'D%' and c.dept_name = 'History'
group by s.name, s.id
having count(distinct c.course_id) >= 5
The WHERE clause returns all students whose names start with a 'D' and have taken at least one course in history department. The HAVING clause filters out any students with 4 or less distinct courses in history department.

Select students not having any corresponding course

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

How to count students and classes of every teacher in SQL Server?

Assume 3 tables like this:
Teacher:
teacher_id, name, ...
Student:
student_id, teacher_id, ...
Class:
class_id, teacher_id, ...
Is there a SQL query to get how many students and classes are assigned to every teacher?
Result should be something like this:
teacher_id name students classes
t_001 AAA 3 2
t_002 BBB 1 2
...
Try something like this:
SELECT
t.teacher_id, t.name,
Classes = (SELECT COUNT(*) FROM Class c WHERE c.teacher_id = t.teacher_id),
Students = (SELECT COUNT(*) FROM Student s WHERE s.teacher_id = t.teacher_id)
FROM teacher t
with teacher_students as (
select t.teacher_id,
t.name,
count(s.student_id) as students
from Teacher t
left outer join Student s
on t.teacher_id = s.teacher_id
group by t.teacher_id, t.name
),
teacher_classes as (
select t.teacher_id,
count(c.class_id) as classes
from Teacher t
left outer join Class c
on t.teacher_id = c.teacher_id
group by t.teacher_id
)
select ts.teacher_id,
ts.name,
ts.students,
tc.classes
from teacher_students ts
join teacher_classes tc
on ts.teacher_id = tc.teacher_id
try this:
SELECT T.TEACHER_ID
, T.NAME,
, COUNT(C.TEACHER_ID ) AS CLASSES
, COUNT(S.TEACHER_ID ) AS STUDENTS
FROM TEACHER T
LEFT OUTER JOIN CLASS C
ON T.TEACHER_ID = C.TEACHER_ID
LEFT OUTER JOIN STUDENT S
ON T.TEACHER_ID = S.TEACHER_ID
GROUP BY T.TEACHER_ID, T.NAME