Making a SQL query (cross table) - sql

I am revising for my exam and I am a bit struggling with SQL queries..
Task for me is:
write a SQL query to list the full names of all the clients that
attend Allen Moore‟s classes, in alphabetical order of surname (i.e.
Lname column)
Client
Cid Fname Lname Fitness
C129 Julie Summer 1
C525 Max Hedrum 3
C628 John Long 3
C772 Warren Peace 2
C829 Anna Heart 2
Programme
Code Title Fitness
AR02 Aerobics 2
EN99 Endurance 3
TU10 Tune-Up 1
UB01 Upper-Body 2
YG02 Yoga 1
Staff
Sid Fname Lname Position Salary
S09 Jenny Sayer Psychologist 23500
S22 Allen Moore Instructor 21500
S28 Polly Purves Instructor 19000
S35 Jim Shoe Instructor 18000
S55 Mark Spencer Manager 25500
Class
Code Sid Cid
AR02 S35 C772
EN99 S22 C525
TU10 S35 C129
UB01 S28 C628
YG02 S22 C829
YG02 S22 C12
Is it something like:
SELECT Cliente.Fname, Cliente.Lname
FROM Staff, Class, Cliente
WHERE Staff.Sid = Class.Sid AND Staff.Fname = "Allen" AND Staff.Lname = "Moore
AND Class.Cid = Cliente.Cid
GROUP BY Cliente.lName ASC;
Thanks!

select c.fname + ' ' + c.lname
from Client c
inner join Class cl
on c.cid = cl.cid
inner join Staff s
on s.sid = cl.sid
where s.fname = 'allen'
and s.lname = 'moore'
order by c.lname

Using different aliases and a more popular convention for JOINs, but your query should also work. Also, ORDER BY ascending is default, so ASC is optional...
SELECT CLNT.Fname, CLNT.Lname
FROM Class AS CLS
INNER JOIN Client AS CLNT ON CLS.Cid = CLNT.Cid
INNER JOIN Staff AS S ON CLS.Sid = S.Sid
WHERE S.Fname = 'Allen'
AND S.Lname = 'Moore'
ORDER BY CLNT.Lname;

The GROUP BY in your query has to go, you don't have to aggregate anything. I would prefer the SQL92 syntax for a join:
SELECT
Client.Fname, Client.Lname
FROM
Staff
INNER JOIN
Class ON Staff.Sid = Class.Sid AND Staff.Fname = "Allen" AND Staff.Lname = "Moore"
INNER JOIN
Client ON Class.Cid = Cliente.Cid
ORDER BY Cliente.lName ASC;

Try brushing up on your use of the JOIN...ON clause.
http://www.w3schools.com/sql/sql_join_inner.asp

Since none of the information from other tables is actually being used, why JOIN at all?
SELECT FName, LName
FROM Client
WHERE
Cid IN (
SELECT Cid
FROM Class
WHERE Sid = (
SELECT Sid FROM Staff WHERE FName = 'Allen' AND LName = 'Moore'
)
)
ORDER BY LName ASC;

Related

Need Simple SQL direction

I'm trying to write a Ado SQL statement for my Access table and I'm getting the wrong results.
Employee Table
ID Name DriverID
1 Alex 1
2 Tom 2
3 Trevor 3
4 PHIL 0
5 Gina 4
Vehicle Table
ID PLATE EMPLOYEEID INSERVICE
1 123XYZ 1 N
2 456GFR 2 Y
3 TFV4FG 3 Y
4 F6GK7D 4 Y
5 GEY7GH 1 Y
I want result of All employes and to display the Vehcicle info if they are assigned to it.
Result should be
Name Plate
Alex GEY7GH
Tom 456GFR
Trevor TFV4FG
PHIL
Gina F6GK7D
SELECT Employee.ID, Employee.FirstName, Vehicles.Plate, Vehicles.InService
FROM Employee LEFT JOIN Vehicles ON Employee.ID = Vehicles.DriverID
WHERE (((Vehicles.InService)=True));
Does not display PHIL who is not assigned to a vehicle.
Just add the condition inside the join, making sure to use parentheses to avoid problems when joining with constants or anything but simple equals:
SELECT Employee.ID, Employee.FirstName, Vehicles.Plate, Vehicles.InService
FROM Employee LEFT JOIN Vehicles ON (Employee.ID = Vehicles.DriverID AND Vehicles.InService = True)
From the above tables, it looks like the DriverID Column in employee table aligns with the EmployeeID column in the vehicles table and the issue is the on clause in the join.
SELECT
Employee.ID
,Employee.FirstName
,Vehicles.Plate
,Vehicles.InService
FROM
Employee
LEFT JOIN Vehicles ON Employee.DRIVERID = Vehicles.EMPLOYEEID
WHERE
(((Vehicles.InService)=True));
Well, in a normal database, you would move the WHERE condition to the ON clause. But I don't think that MS Access supports this:
SELECT e.ID, e.FirstName, v.Plate, v.InService
FROM Employee as e LEFT JOIN
Vehicles as v
ON e.ID = v.DriverID AND v.InService = True;
An alternative is a subquery:
SELECT e.ID, e.FirstName, v.Plate, v.InService
FROM Employee as e LEFT JOIN
(SELECT v.*
FROM Vehicles as v
WHERE v.InService = True
) as v
ON e.ID = v.DriverID ;

Find records for students missing a class

I have two tables, one that flags a user as having passed a course, and a list of courses per job code. I'm trying to query to return a record for all users that are missing classes.
Here are the tables:
Attended
--------
empid jobcode classcode grade
555 1 100 A
555 1 101 A
444 2 200 A
JobClassCode
--------
jobcode classcode
1 100
1 101
1 102
2 100
2 200
3 300
3 301
I started with this query to find classes with a missing user:
select * from attended at
right outer join jobcodeclass jc on at.jobcode = jc.jobcode and at.classcode = jc.classcode
I then tried to take that to build a correlated subquery, but I don't see a way to return both the user ID and missing course ID:
select * from jobcodeclass oq where classcode in (select jc.classcode from attended at
right outer join jobcodeclass jc on at.jobcode = jc.jobcode
and at.classcode = jc.classcode and jc.jobcode = oq.jobcode
and oq.classcode = jc.classcode and empid is null)
Generate all the possible classes that each employee needs by joining on the jobcode. The see which ones the student attended:
select ej.empid, ej.jobcode, jss.classcode
from (select distinct empid, jobcode from attended) ej join
JobClassCode jcc
on jcc.jobcode = ej.jobcode left join
attended a
on a.empid= e.empid and a.jobcode = ej.jobcode and
a.classcode = jcc.classcode
where a.empid is null;
If you just need the employees, use select distinct ej.empid.

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

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)