How to query for many to many relationship in Sql Server - sql

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)

Related

Native Query to Select records to only contain specific ids

I am in the process of implementing an advanced search in my application. I'm sort of new with Oracle and JPA. The database structure has a many-to-many relationship (ERD) with an intermediate table that contains StudentID and CourseID.
I'm trying to return rows of students that have the list of classes/courses.
Basically, I want the results of
SELECT DISTINCT s.* FROM STUDENT s
INNER JOIN STUDENT_COURSE sc ON s.StudentID = sc.StudentID
INNER JOIN COURSE c ON c.CourseID = sc.CourseID
WHERE ( c.CourseID IN (SELECT DISTINCT CourseID FROM STUDENT_COURSE WHERE CourseID = 'A01') AND c.CourseID IN (SELECT DISTINCT CourseID FROM STUDENT_COURSE WHERE CourseID = 'A02'));
which returns the records of students that have both courses 'A01' and 'A02'.
ID
Age
Grade
1
...
...
4
...
....
9
...
....
with courses
Courses
A01,A02
A01,A02,A03,X02
A01, A02, A03
The goal is to get a similar result using Spring Data JPA. And make it more general to select any number of Course Ids.
I've tried
#Query(value="SELECT DISTINCT s.* FROM STUDENT s "
+"INNER JOIN STUDENT_COURSE sc ON s.StudentID = sc.StudentID "
+"INNER JOIN COURSE c ON c.CourseID = sc.CourseID "
+"WHERE ( s.STUDENTID IN (SELECT DISTINCT STUDENTID FROM STUDENT_COURSE WHERE CourseID =:courseIds)",nativeQuery=true))
public List<Student> advancedSearch(#Param("courseIds") String courseIds);
One example, The courseIds field contain "A01,A02". The result would be empty.
I've looked at examples where people use IN. When I tried it, it would return records of the student have courses AO1 OR A02 OR Both.
DON'T WANT THIS
ID
Age
Grade
2
...
...
3
...
....
8
...
....
With Courses
CourseID
A01,A03
A01, X01
A02
I want records of students that have both A01 AND A02 as shown in the other table.
My guess is that the query you want is
select s.name /* note this column doesn't appear in your ERD */
,s.age
,s.grade
from student s
join student_course sc
on s.studentID = sc.studentID
where sc.courseID IN ('A01', 'A02')
group by s.name /* again, this column isn't in your ERD */
,s.age
,s.grade
having count(sc.courseID) = 2
That doesn't produce the output table you say you want. But neither does the query you posted. This will return all the students that have taken both courses (you could add a distinct to the having clause if the data model were to change to allow a student to take a course multiple times). It won't give you the list of all courses that student has taken as a comma-separated list. But the query you posted doesn't return any course information either.
If this isn't what you are looking for, it would be really helpful to update your question with
The DDL for your schema in text form (so we can run it) rather than as an image
The DML to insert whatever sample data you want
The actual results you'd want the query to return (since there is a conflict between what the query you posted returns, the table of data you say you want, and the descriptive text of what you are trying to accomplish, it is confusing to try to figure out which is right).

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;

SQL query - list of items in one table not in another

I need some help with a SQL query. I have a table of courses and a table that contains user id and course id, denoting courses that user has taken (might not have taken any; no entry in that table for that user id).
I need a query to return the list of courses not taken.
Course Category table
CategoryID
Caegory
Courses table
CourseID
CategoryID
CourseName
...
UserCourse table
UserID
CourseID
you can use not exists
Select *
From Courses c
Where Not Exists (Select 1 From UserCourse uc Where uc.CourseID = c.CourseID)
This will just list the course
select *
from Courses C
Left join CourseCategory cc on
cc.CategoryID = c.CategoryID
where CourseID not in (Select CourseID from UserCourse where UserID = 14)
what i need is for a given user id and course category, what courses within that category have not been taken by this user
(This should have been in the request by the way.)
So:
Select from courses.
Limit to the desired category.
Limit to courses not in the set of courses taken by the user.
The query:
select *
from courses
where categoryid = 123
and courseid not in (select courseid from usercourse where userid = 456);
Another way of writing same query, which will perform faster.
select C.CourseID,C.CategoryID
from Courses C
Left join CourseCategory cc on
cc.CategoryID = c.CategoryID
left join UserCourse uc
on C.CourseID=uc.CourseID
where uc.CourseID is null

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

Selecting records from a many-to-many design

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)