Find missing records in ONE-TO-MANY relationship query - sql

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'

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)

Combining window functions and conditions

Consider the classic Student and Classes many-many relationship, where a student can attend multiple classes and a class contains multiple students.
CREATE TABLE students(
id serial PRIMARY KEY,
name text,
gender text NOT NULL
);
CREATE TABLE schools(
id serial PRIMARY KEY,
name text,
);
CREATE TABLE classes(
id serial PRIMARY KEY,
name text,
school_id integer NOT NULL REFERENCES schools (id)
);
CREATE TABLE students_classes(
id serial PRIMARY KEY,
class_id integer NOT NULL REFERENCES classes (id),
student_id integer NOT NULL REFERENCES students (id),
);
The overall query is much bigger - consider that there are schools and other things that add to the complexity of the problem. So I need to use window functions to get things like total_students.
I want a query that gets me all the classes, the total number of students enrolled in that class, the number of guys enrolled and the number of girls.
class_id | n_students | n_guys | n_girls
____________________________________________
| | |
I have the following so far, can I get some help the number of guys and girls?
SELECT
school_id,
w.class_id,
w.n_students,
w.n_guys,
w.n_girls
FROM schools
JOIN classes ON classes.school_id = schools.id
JOIN (
c.id AS class_id,
COUNT(*) OVER (PARTITION BY sc.class_id) AS n_students,
{Something} AS n_guys,
{Something} AS n_girls
FROM students_classes AS sc
JOIN classes AS c ON sc.class_id = c.id
) as w ON w.class_id = classes.id
WHERE school_id = 81;
You could use this, no need to use windows/analytic function
Change male and female to your text value of your students.gender column
SELECT
s.school_id,
c.class_id,
COUNT(*) AS n_students,
SUM(CASE WHEN st.gender = 'male' THEN 1 ELSE 0 END) AS n_guys,
SUM(CASE WHEN st.gender = 'female' THEN 1 ELSE 0 END) AS n_girls
FROM schools s
INNER JOIN classes c
ON c.school_id = schools.id
INNER JOIN students_classes sc
ON sc.class_id = classes.id
INNER JOIN students st
ON st.id = sc.student_id
WHERE s.school_id = 81
GROUP BY s.school_id, c.class_id
ORDER BY s.school_id, c.class_id;
Because you are just using the id, you do not need the schools table. So, this query is basically joins with conditional aggregation:
select c.school_id, c.id as class_id,
count(*) AS n_students,
sum( (st.gender = 'male')::int ) AS n_guys,
sum( (st.gender = 'female')::int ) AS n_girls
from classes c join
students_classes sc
on sc.class_id = c.id join
students st
on st.id = sc.student_id
where c.school_id = 81
group by c.school_id, c.id
order by c.school_id, c.id;

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

Linking of field data to field name between two tables

I have one table name Class_sub where I have subjects name according to the classes, I have weekly_test table where the same subject's marks have to be entered.
My problem is to show subject name as field name in weekly_test table reference to class_sub table data fields.
If you have the following tables:
CLASS
id
name
SUBJECT
id
name
CLASS_SUBJECT
id
class_id
subject_id
WEEKLY_MARKS
id
class_subject_id
test_date
mark
The following query will work:
SELECT s.name as subject_name,
c.name as class_name,
wm.test_date,
wm.mark
FROM weekly_marks wm
INNER JOIN class_subject cs ON wm.class_subject_id = cs.id
INNER JOIN class c ON cs.class_id = c.id
INNER JOIN subject s ON cs.subject_id = s.id
A bit of a guess here, but assuming the class_subject table you're talking about is joining of subjects (students?) to the classes they are enrolled in.

SQL Query (or Join) for 3 tables

first time asking a question on Stack Overflow... Amazing resource, but there's just one thing that's really baffling me as a newcomer to SQL.
I have three tables and I would like to obtain the names of all the Mentors who are linked to Bob's students.
Table 1: TEACHERS
================
ID Name
================
1 Bob
Table 2: STUDENTS
===================================
STUDENT_ID Name TEACHER_ID
===================================
1 Jayne 1
2 Billy 5
3 Mark 2
Table 3: MENTOR_RELATIONSHIPS
==============================
ID STUDENT_ID MENTOR_ID
==============================
1 1 3
2 2 2
3 3 3
Table 4: MENTORS
=====================
MENTOR_ID Name
=====================
1 Sally
2 Gillian
3 Sean
I would like to run a query to find all of the mentors of Bob's students. So the mentors for all students with TEACHER_ID = 1
In this case Sean would be the result.
I know that it is something to do with Joins, or could I find this using a normal query??
Any help is much appreciated! Many thanks...
this should do the work
select distinct m.name from students s
inner join mentor_ralationships mr on mr.student_id=s.student_id
inner join mentors m on m.mentoir_id=mr.mentor_id
where s.teacher_id=1;
Without joins (not preferred)
SELECT mentors.name FROM mentors
WHERE mentors.id
IN (SELECT MENTOR_RELATIONSHIPS.mentor FROM MENTOR_RELATIONSHIPS
WHERE MENTOR_RELATIONSHIPS.student
IN (SELECT students.id FROM students WHERE students.teacher
= (SELECT teachers.id FROM teachers WHERE teachers.name = 'bob')));
It could be helpful for you as I had to retrieve data from three tables AssignedSubject, Section and SchoolClass when a teacher assigned to specific subject then I have to find out the his class and section details including subjectid which I did this way
select a.StaffID, a.SubjectID, s.ID as SectionId, s.Name as SectionName, S.Remarks as SectionRemarks, sc.ID as ClassId, sc.Name as ClassName, sc.Remarks as ClassRemarks from AssignedSubject a
inner join Section s on a.SectionId=s.ID
inner join SchoolClass sc on sc.ID=s.ClassId where a.StaffID=3068
You could try the following:
SELECT DISTINCT m.name
FROM students s INNER JOIN TEACHERS t ON t.ID = a.TEACHER_ID
INNER JOIN MENTOR_RELATIONSHIPS mr ON mr.Student_id = s.Student_id
INNER JOIN Mentors m ON mr.MENTOR_ID = s.MENTOR_ID
WHERE s.teacher_id = 1 WHERE t.Name = 'Bob';
SELECT TEACHER.NAME, STUDENTS.NAME AS STUDENT NAME, MENTORS.NAME AS MENTOR
FROM TEACHERS JOIN STUDENTS ON TEACHERS.ID = STUDENTS.TEACHER_ID
JOIN MENTOR_RELATIONSHIPS ON STUDENTS.STUDENT_ID =
MENTOR_RELATIONSHIPS.STUDENT_ID
JOIN MENTORS ON MENTOR_RELATIONSHIPS.MENTOR_ID = MENTORS.MENTOR_ID
WHERE TEACHER.NAME = 'Bob' ;