Selecting records from a many-to-many design - sql

There are three tables, Students, Classes, Student_Class
Is it possible to select students who are not registered in any classes without using NOT IN?
e.g. Select studentname from Students Where studentid NOT IN (Select Distinct studentid From Student_Class)

I really don't know why you don't want to use NOT IN, but here's one other option...
SELECT Studentname
FROM Students
LEFT JOIN Student_Class ON Student_Class.StudentID = Student.ID
WHERE Student_Class.StudentID IS NULL

There are three methods:
SELECT StudentName FROM Students WHERE StudentID NOT IN (SELECT StudentID FROM StudentClass);
SELECT StudentName FROM Students s WHERE NOT EXISTS (SELECT StudentID FROM StudentClass WHERE StudentID = s.StudentID); and
SELECT StudentName FROM Students s LEFT OUTER JOIN StudentClass sc ON s.StudentID = sc.StudentID WHERE sc.StudentID IS NULL).
And I really wouldn't use (3). So pick one.
WHERE EXISTS/WHERE NOT EXISTS is often preferred to IN/NOT IN. Modern optimizers will probably optimize (1) and (2) to being the same a lot of the time. It's worth comparing performance (when it matters).

Select studentname from Students s Where s.studentid NOT EXISTS (Select 1 From Student_Class sc where sc.studentid = s.studentid)

Related

Getting data from unrelated tables

I've got this homework for database 'SCHOOL'
Table Student (StudentID, Name, Surname, etc..)\
Table Application (ApplicationID, StudentID, ClassID)\
Table Class (ClassID, ClassName, TeacherID)\
Table Teacher (TeacherID, Name, Surname, etc..)
There are some other tables and columns in the database but I don't think they're important to this query.
I need to get name of the teachers for whose classes no student signed up. Let's say there is no one signed up for Math class, and I need to get the name of the teacher for that Math class.
SELECT Teacher.Name, Teacher.Surname, Class.ClassName
FROM Teacher
INNER JOIN Class ON Class.TeacherID = Teacher.TeacherID
INNER JOIN Application ON Application.ClassID = Class.ClassID
INNER JOIN Student ON Student.StudentID = Application.StudentID
WHERE Application.PredmetID IS NULL
Help would be appreciated.
I would recommend NOT EXISTS:
select t.name
from class c join
teacher t
on t.teacherid = c.teacherid
where not exists (select 1
from application a
where a.classid = c.classid
);
I need to get name of the teachers for whose classes no student signed up
Select T.name
From Teacher T inner join [Class] C on T.TeacherId = C.TeacherId
Where C.ClassId not in (Select Distinct ClassId from Application)

T-SQL query to return row with no connected Users

Using a T-SQL return CourseName of a course with no students in it.
StudentCourses:
StudentCourseID
StudentID
CourseID
Courses:
CourseID
CourseName
I have to find what CourseName has no students in it.
Maybe my brain is fried because I don't know where to begin.
Would I need a Left Join for this?
Using the not exists operator would probably be the easiest way of doing this:
SELECT coursename
FROM course c
WHERE NOT EXISTS (SELECT *
FROM studentcourses s
WHERE s.courseid = c.courseid)
You can do this using LEFT JOIN - it will return all courses and the corresponding students. Using WHERE clause we are filtering only this courses which do not have students:
SELECT coursename
FROM course c
LEFT JOIN studentcourses sc
ON c.courseid = sc.courseid
WHERE sc.courseid IS NULL;

How to query for many to many relationship in Sql Server

Here is my tables
My question is How to get CourseNames for a specific student id
I tried this but didn't work
select Course.CourseName from Course
where Course.CourseId in (
select Student.studentname ,StudentCourse.CourseId from Student inner join StudentCourse
on Student.StudentId = StudentCourse.StudentId
where Student.StudentId = 1)
You can forget my query because i am new in SQL Server just tell me what exactly developers do in SQL Server real-world to get course names of a specific student
As you said you want to know the approach this is just basic viewpoint
1) We want to look at CourseName's.
SELECT CourseName FROM Course
2) One Student may have more than one Courses.
3) So we have one more table which is StudentCourse to achieve this.
4) We have to look CourseName's ID'S in this table
SELECT CourseID FROM StudentCourse
5) to find which students(X is a number you seach for) takes those courses.
WHERE StudentID = X
6) If we look them together, we now have all CourseName's via step 1. But we don't want all CourseName's and we have all CourseID's which X numbered student takes. So if we get them together, now we will just select CourseName's which X takes.
WHERE CourseID IN
7) So our final result is
SELECT CourseName FROM Course WHERE CourseID IN
(SELECT CourseID FROM StudentCourse WHERE StudentID = X)
Check this or this one to see how it works.
I'm using left joins just in case your student doesn't have any courses assigned, otherwise, if you use inner joins, you'll get no results;
SELECT
s.StudentID
,s.StudentNam
,sc.CourseID
,c.CourseName
FROM Student s
LEFT JOIN StudentCourse sc
ON s.StudentID = sc.StudentID
LEFT JOIN Course c
ON sc.CourseID = c.CourseID
WHERE s.StudentID = 1
try this:
select CourseName from Course
where CourseId in
(select CourseId from StudentCourse
where StudentId = 1)

Multiple joins onto same table

i have the following tables:
TABLE: teachers:
teacherID
teacherName
TABLE: students:
studentID
studentName
teacherID
advisorID
so, usually, i know i can get a single row per student, with their teachers name using an INNER JOIN.
but in this case - the advisor and tacher - are from the same teachers table. so how can i join onto the teachers table twice - once getting the teacher name, and then again to get the advisor name?
hope this is clear
thanks!
This lists students with the names of their teachers and advisors if any, in alpha order of student, without either (a) the teacher or (b) the advisor having to exist. If you want only where those names exist, change the respective join to an INNER join.
SELECT s.studentname as [Student], t.teachername as [Teacher], a.teachername as [Advisor]
FROM Students s
LEFT JOIN Teachers t ON s.TeacherID = t.TeacherID
LEFT JOIN Teachers a ON s.AdvisorID = a.TeacherID
ORDER BY 1, 2
You can join to the same table more than once, just give it a different alias for each join, and name your fields in a descriptive enough way. Use a left join if there might not be a link, but if a student always has both a teacher and an advisor, a straight join should be fine.
Something like this:
select s.studentname student
, t.teachername teacher
, a.teachername advisor
from students s
join teacher t
on t.teacherID = s.teacherID
join teacher a
on a.teacherID = s.teacherID
Why not try something like the following. Its been a while since I've done SQL so this may not work.
SELECT s.studentName AS Student, t.teacherName AS Teacher, a.teacherName AS Advisor
FROM teachers t, teachers a, students s
WHERE t.teacherID = s.teacherID AND a.teacherID = s.advisorID

LEFT JOIN confusion -- I need to retrieve a student count

I have four tables:
students
classes
teachers
teacher_assignments
classes and teachers has a many-to-many relationship and so teacher_assignments acts as the xref table (with fields teacher_id and class_id).
Each student in students has a class_id (many-to-one -- many students to one class).
I should also mention that teacher_assignments has an active column (BOOL) which indicates whether that assignment is currently active
What I want to do:
I want to retrieve the following:
class_name -- a concat of its level and sub_level, e.g. 3 and A
teacher_names -- the names of the teachers currently assigned to that class
student_count -- a count of the students in each class
At first, I tried retrieving just the class_name and teacher_names, like so:
SELECT
CONCAT(CONVERT(classes.level, CHAR(8)), classes.sub_level) AS class_name,
GROUP_CONCAT(DISTINCT teachers.name SEPARATOR ',') AS teacher_names
FROM
teacher_assignments
LEFT JOIN teachers
ON teachers.id = teacher_assignments.teacher_id
AND teacher_assignments.active = TRUE
LEFT JOIN classes
ON classes.id = teacher_assignments.class_id
GROUP BY classes.id
This works fine and outputs:
class_name | teacher_names
--------------------------------------
1A | NULL
2A | John, Sam
3B | Sam, Sarah
(Class 1A has no teachers currently, and so the NULL is expected)
... BUT, now I have no idea how to work the student_count into this.
My question:
How exactly should the students table be joined with the others in the above query so I can produce a student_count column?
Use:
SELECT CONCAT(CONVERT(c.level, CHAR(8)), c.sub_level) AS class_name,
GROUP_CONCAT(DISTINCT teachers.name SEPARATOR ',') AS teacher_names,
COUNT(s.id) AS studentCount
FROM CLASSES c
LEFT JOIN TEACHER_ASSIGNMENTS ta ON ta.class_id = c.id
AND ta.active = TRUE
LEFT JOIN TEACHERS t ON t.id = ta.teacher_id
LEFT JOIN STUDENTS s ON s.class_id = c.id
GROUP BY class_name
Column aliases can be referenced in the GROUP BY when using MySQL, otherwise you'd have to duplicate the logic that produces the class_name column value. This is also the column to GROUP on, as GROUP_CONCAT and COUNT are aggregate functions.
To get zero as the count value, you might need to use:
SELECT CONCAT(CONVERT(c.level, CHAR(8)), c.sub_level) AS class_name,
GROUP_CONCAT(DISTINCT teachers.name SEPARATOR ',') AS teacher_names,
COALESCE(COUNT(s.id), 0) AS studentCount
FROM CLASSES c
LEFT JOIN TEACHER_ASSIGNMENTS ta ON ta.class_id = c.id
AND ta.active = TRUE
LEFT JOIN TEACHERS t ON t.id = ta.teacher_id
LEFT JOIN STUDENTS s ON s.class_id = c.id
GROUP BY class_name
Just thinking off the top of my head...
Join classes and students tables to get the student count...
Instead of doing a left join on classes in your above query, you will do a left join with the result from #1 (essentially an inner join between classes and students tables) that allows you to pull the student count.
I dont think I would use a join but instead would use an inline column select on student like this:
SELECT
CONCAT(CONVERT(classes.level, CHAR(8)), classes.sub_level) AS class_name,
GROUP_CONCAT(DISTINCT teachers.name SEPARATOR ',') AS teacher_names,
( SELECT COUNT(*) FROM students WHERE students.class_id = classes.id ) AS student_count
FROM ...