SQL Query (or Join) for 3 tables - sql

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' ;

Related

Count the sum of a left outer join table

I have two tables which is
Student
ID
Name
Gender
Address
1
Abby
Girl
street
2
Mark
Boy
street
3
Lula
Girl
street
4
Bren
boy
street
Lessons
ID
Lessons_code
3
MK2234
5
22324KL
6
KCS233
and I want to join these tables then get the sum result of the students that didn't took a lesson then group it by gender like this:
Gender
total
Boy
2
girl
1
I know it use sum() and left outer join (?) but I don't know how to implement it.
I would suggest not exists:
select s.gender, count(*)
from students s
where not exists (select 1
from lessons l
where l.id = s.id
)
group by s.gender;
You have a very awkward data model. I would expect a column called lessons.id to refer to the primary key of the lessons table. Instead. it seems to refer to a student. A better name would be student_id.

Combine data and non data rows in SQL

Table : Mark M [Id, Subject, Mark]
Test Student Ids: 100, 101
Requirement: We need mark of both students of subject 'Maths'.
Condition: Student (101) was absent for Maths exam. So there wont be any record in Mark table for the student 101.
Expected Result:
Student ID Subject Mark
100 Maths 45
101 Maths 0
I.e. We need to add an additional row with Subject=Maths and Mark=0 for student 101
Thanks in advance
You can try using left join
select * from students a left join marks b
on a.studentid=b.studentid
you could use left join
select s.*, m.*
from student s
left join Mark m on m.Id = s.id
left join retrive row also if the values don't match
Assuming you have multiple subjects and are only interested in math, then you need to be careful about filtering:
select s.*, 'Maths' as subject, coalesce(m.mark, 0) as mark
from student s left join
mark m
on m.Id = s.id and m.subject = 'Maths';

Joining two tables and display data from first table

I have two tables tblPatient, tblDropDowns
tblpatient:
firstname gender patienttype
anil 1 3
Satheesh 1 4
Vinod 1 4
Shashikanth 1 3
Srimani 2 3
Thanuja 2 4
Nandini 2 4
Vishu 2 3
and
tblDropdowns:
id Name
1 Male
2 Female
3 Inpatient
4 Outpatient
Now i want to display the patient table with gender and patient type as their significant names are connected to dropdown table.
result table:
firstname gender patienttype
anil male inpatient
satheesh male outpatient
vinod male outpatient
please help me out..
thanks
anil
In general it would be better avoid storing different things in the same table. However, you could join with subqueries that only contain the relevant records.
SELECT firstname, gender.Name AS gender, patienttype.Name As patienttype
FROM tblPatient p
INNER JOIN (SELECT id, Name
FROM tblDropdowns
WHERE id IN (1, 2)) gender
ON p.gender = gender.id
INNER JOIN (SELECT id, Name
FROM tblDropdowns
WHERE id > 2) patienttype
ON p.patienttype = patienttype.id
Please try out this.
select [column1], [column2] from tblpatient a, tbldropdowns b
where a.gender = b.id order by a.gender;
You could also use joins: Please refer this W3Schools SQL Link.
Hope this helps. Thanks.
Edit
Maybe this query could be your solution:
select a.firstname, b.name as 'gender', b.name as 'PatientType'
from tblpatient a, tbldropdowns b
where a.gender = b.id and a.patienttype = b.id
order by a.gender;
Thanks again. :-)
Try as follows:
SELECT firstname, name, CASE WHEN (patienttype=3) THEN 'inpatient' ELSE 'outpatient' END as patienttype_text from tblpatient INNER JOIN tbldropdowns ON gender = id
join your "tblDropdowns" table twice in your select query.
Please refer this link to understand join,
http://www.w3schools.com/sql/sql_join_left.asp
select tP.firstname,tG.Name gender,tPT.Name patienttype
from tblPatient tP
left join tblDropDowns tG
on tG.id = tP.gender
left join tblDropDowns tPT
on tPT.id = tP.patienttype

Complicated table join

I thought I had a good grasp on table joins but there is one problem here I can't figure out.
I am trying to track the progress of students on specifically required courses. Some students are required to complete an exact list of courses before further qualification.
Tables (simplified):
students
--------
id INT PRIMARY KEY
name VARCHAR(50)
student_courses
---------------
student_id INT PRIMARY KEY
course_id TINYINT PRIMARY KEY
course_status TINYINT (Not done, Started, Completed)
steps_done TINYINT
total_steps TINYINT
date_created DATETIME
date_modified DATETIME
courses
-------
id TINYINT PRIMARY KEY
name VARCHAR(50)
I want to insert a list of required courses, for example 5 different courses in the courses table and then select a specific student and get list of all the courses required, whether a row exists for that course in the student_courses table or not.
I guess I could insert all rows from the courses table in the student_courses table for each student, but I don't want that because not all students need to do these courses. And what if new courses are added later.
I just want a result which is something like this:
students table:
id name
--- ------------------
1 George Smith
2 Dana Jones
3 Maria Cobblestone
SELECT * FROM students (JOIN bla bla bla - this is the point where I'm lost...)
WHERE students.id = 1
Result:
id name course_id courses.name course_status steps_done
--- ------------------ --------- ------------ ------------- ----------
1 George Smith 1 Botany Not started 0
1 George Smith 2 Biology NULL NULL
1 George Smith 3 Physics NULL NULL
1 George Smith 4 Algebra Completed 34
1 George Smith 5 Sewing Started 2
If the course_status or steps_done is NULL it means that no row exists for this student for this course in the student_courses table.
The idea is then using this in MS Access (or some other system) and have the row automatically inserted in the student_courses table once you enter a value in the NULL field.
You can't just use an outer join to do this, you need to create a list of all students/classes combinations that you're interested in first, then use that list in a LEFT JOIN. Can be done in a cte/subquery using CROSS JOIN:
;WITH cte AS (SELECT DISTINCT s.id Student_ID
,s.name
,c.id Course_ID
,c.name Class_Name
FROM Students s
CROSS JOIN Courses c)
SELECT cte.*,sc.status
FROM cte
LEFT JOIN student_courses sc
ON cte.course_id = sc.course_id
Can also use a subquery if needs to be done in Access (not 100% on syntax in Access):
SELECT sub.*,sc.status
FROM (SELECT DISTINCT s.id Student_ID
,s.name
,c.id Course_ID
,c.name Class_Name
FROM Students s
CROSS JOIN Courses c
) AS sub
LEFT JOIN student_courses sc
ON sub.course_id = sc.course_id
Demo: SQL Fiddle
You want a left outer join. The first table is from the courses table and is used for the required courses (defined in the where clause).
select s.id, s.name, c.id, c.name, c.course_status, c.steps_done
from (courses as c left join
student_courses as sc
on sc.course_id = c.id and
sc.student_id = 1
) left join
students as s
on sc.student_id = s.id
where c.id in (<list of required courses>)
order by s.id, c.id;
I think I have all the "Access"isms in there.
Actually, the above will be missing the student name when s/he is missing a course. The following is more correct:
select s.id, s.name, c.id, c.name, c.course_status, c.steps_done
from (courses as c left join
student_courses as sc
on sc.course_id = c.id and
sc.student_id = 1
) cross join
students as s
on s.id = 1
where c.id in (<list of required courses>)
order by s.id, c.id;

sql foreach without using cursor

I have a table "Student" in sql with a structure:
StudentId FirstName LastName
1 X Y
....
AND a table of Languages ,its structure:
LanguageId Name
1 English
2 Mandarin
3 Spanish
.....
and a relationship table StudentLanguage (languages spoken by a student)
StudentId LanguageId
1 1
1 3
2 1
2 2
from my asp.net page i want to filter students by spoken languages using checkboxes.
for example,when i check English,Madarin i want to have students speaking both English and Madarin
When i check French,Spanish ,English ==>Get students speaking French,AND English,AND Spanish.
to do that i pass a table of Languages paramter called #LanguageTable(LanguageId smallint) to a stored procedure.
how can i use this table to get the students without using a cursor.
I have tried with CTE but no result.
Try this:
select s.StudentId,s.FirstName,s.LastName
from Stundent s
join StudentLanguage sl on s.StudendID=sl.StudentId
join #LanguageTable on sl.LanguageId=#LanguageTable.LanguageId
group by s.StudentId,s.FirstName,s.LastName
having count(*)=(select count(*) from #LanguageTable)
You need relational division.
SELECT s.StudentId, s.FirstName, s.LastName
FROM Student s
WHERE NOT EXISTS(SELECT *
FROM #LanguageTable l
WHERE NOT EXISTS(SELECT *
FROM StudentLanguage sl
WHERE sl.LanguageId = l.LanguageId
AND sl.StudentId = s.StudentId))
I haven't tested this but:
SELECT s.StudentId, s.FirstName, s.LastName
FROM Student s
INNER JOIN StudentLanguage sl ON sl.StudentId = s.StudentId
INNER JOIN #Language l ON l.LanguageId = sl.LanguageId
GROUP BY s.StudentId, s.FirstName, s.LastName
HAVING Count(*) = (SELECT COUNT(*) FROM #Language)