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

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

Related

How do i make this query with two conditions?

database structure
Professor
prof_id number
name string
salary number
building string
Course
name string
prof_id number
room_number number
start_time number
end_time number
Room
room_number number
capacity number
building string
Professors with at least 1 math course:
select distinct Professor.name, count(Course.name) AS numberOfMathCourses
from Course
LEFT JOIN Room
ON Course.Room_id = Room.Room.id
INNER JOIN Professor
ON Professor.id = Course.id
where Course.name = 'math'
group by Professor.name
having numberOfMathCourses > 0
Professors with less than 3 courses :
select distinct Professor.name, count(Course.name) AS numberOfCourses
from Course
LEFT JOIN Room
ON Course.Room_id = Room.Room.id
INNER JOIN Professor
ON Professor.id = Course.id
group by Professor.name
having numberOfCourses < 3
how would do I create a Query that has both of these conditions ? more than one math course course and less than 3 courses.
I tried sub-queries but I wasn't able to make it work. I will try to look into it more. Thanks for the help.
select *
from Professor p
where
(select count(*) from Course c where p.prof_id = c.prof_id and c.name = 'math') > 0
and (select count(*) from Course c where p.prof_id = c.prof_id) < 3

Find missing records in ONE-TO-MANY relationship query

I have 3 tables:
Class
Id
ClassName
guid
1A
guid
2A
Subject
Id
SubjectName
guid
Math
guid
Biography
SubjectOfEachClass
Id
ClassId
SubjectId
TeacherName
guid
guid
guid
James Bond
The way I wanted these tables to work is:
There will be 10 classes in table Class.
There will be 10 subjects in table Subject.
Each class will has 10 subjects and for 10 classes there will be 100 records.
I ran into some problems, I queried the SubjectOfEachClass table and there are only 95 records.
The query command I use to find the missing subjects is:
SELECT *
FROM Subject s
JOIN (
SELECT *
FROM SubjectOfEachClass
WHERE ClassId = 'guid'
) AS sc ON s.Id = sc.SubjectId
I replaced the ClassId several times until I found the class that misses some of the subjects.
I reckon this way of querying is not efficient at all. If I have 100 subjects and 100 classes, there will no chance that I will find the missing subjects.
to find every missing subject in all classes:
select c.id, c.classname , s.id , s.SubjectName
from class c
cross apply Subject s
where not exists (
select 1 from SubjectOfEachClass sc
where sc.classid = c.id and sc.subjectid = s.id
)
Try this:
SELECT c.id AS classId,
count(sc.id) AS countOfSubjects
FROM SubjectOfEachClass AS sc
INNER JOIN Classes AS c ON c.id = sc.classId
GROUP BY c.id
ORDER BY countOfSubjects
The abnormal values will be floated.
Your primary table should be SubjectOfEachClass, then those foreign tables Subject and Class will join your primary table.
select *
from SubjectOfEachClass sc
inner join Subject s on s.guid=sc.guid
inner join Class c on c.guid=sc.guid
where sc.ClassId = 'guid'

PostgreSQL: How do I get data from table `A` filtered by a column in table `B`

I want to fetch all parents that have kids in a specific grade only in a school.
Below are trimmed down version of the tables.
TABLE students
id,
last_name,
grade_id,
school_id
TABLE parents_students
parent_id,
student_id
TABLE parents
id,
last_name,
school_id
I tried the below query but it doesn't really work as expected. It rather fetches all parents in a school disregarding the grade. Any help is appreciated. Thank you.
SELECT DISTINCT
p.id,
p.last_name,
p.school_id,
st.school_id,
st.grade_id,
FROM parents p
INNER JOIN students st ON st.school_id = p.school_id
WHERE st.grade_id = 118
AND st.school_id = 6
GROUP BY p.id,st.grade_id,st.school_id;
I would think:
select p.*
from parents p
where exists (select 1
from parents_students ps join
students s
on ps.student_id = s.id
where ps.parent_id = p.id and
s.grade_id = 118 and
s.school_id = 6
);
Your question says that you want information about the parents. If so, I don't see why you are including redundant information about the school and grade (it is redundant because the where clause specifies exactly what those values are).

Mapping table join query

I have three tables as follows,
student
category
student_category
Student table has the following columns:
studentid, student name, studenttype
Category table has the following tables:
categoryid, categoryname, ..
student_category table has the following columns:
id, studentid, categoryid
Now I have 2 input parameters categoryid and studenttype so now I need to get the all the student details which are associated with respective categoryid and whose student type is studenttype
I tried as follows which is not giving correct result,
SELECT
s.*
FROM
student s
JOIN
student_category sc ON sc.categoryid = 1;
Also I also need to filter student whose studenttype is 'someinput'
I am working on PostgreSQL. Any suggestions please
You should add a where clause and also use the appropiate join condition.
SELECT s.*
FROM student s
JOIN student_category sc ON sc.studentid = s.studentid
where s.studenttype = 'studenttype' --or your desired value
and sc.categoryid = 1

How to exclude some rows from a SELECT Statement when 2 keys match?

I have 3 tables in my system: Courses, Scores and Users. Scores is a table which has the test results for each course and each user. So I have the ScoreID, The CourseID the UserID and the Score itself.
I want to show in some page the list of courses that the user didn't finished yet. So I want it to show all the courses excluding those the user has records in the Scores table (meaning he already has finished it).
How do I exclude the rows from a SELECT statement when certain CourseID and UserID match at the same time?
Assuming that this is for just one user, Mark Bannister's answer can be simplified a little...
SELECT
*
FROM
Courses
WHERE
NOT EXISTS (SELECT * FROM Scores WHERE CourseID = Courses.CourseID AND UserID = #userID)
Try:
select *
from Courses c
cross join Users u
where not exists
(select null from Scores s where s.CourseID = c.CourseID and s.UserID = u.UserID)
select *
from Courses
where not exists
(
select null from Scores where Scores.CourseID = Courses.CourseID
and Scores.UserID = Courses.UserID
)
Assuming you are using SQL Server you can
CROSS APPLY the courses and users, creating every possible combinations of courses and users
use NOT EXISTS to filter out those records where a UserID exists.
SQL Statement
SELECT *
FROM Courses c
CROSS APPLY Users u
WHERE NOT EXISTS (
SELECT *
FROM Scores
WHERE UserID = u.UserID
AND ScoreID = c.ScoreID
)
In case you are using any other DBMS, following should work on most DBMS's
SELECT *
FROM Courses AS c
, Users AS u
WHERE NOT EXISTS (
SELECT *
FROM Scores
WHERE UserID = u.UserID
AND ScoreID = c.ScoreID
)