Usage of joins: getting the oppsite result - sql

I am working with oracle and below I have a basic sql query where I select the schools that have a team using a join. However I am struggling how can I select the opposite(schools that don’t have a team) using a join as well. I tried using the words outter, inner, left and right but to no avail I get the results that I desired. How can I list the schools that don’t have a team?
Query:
SELECT DISTINCT a.school_name, a.school_id, b.school_id FROM School a RIGHT OUTER JOIN Team b ON a.school_id = b.school_id;
Results:
SCHOOL_NAME SCHOOL_ID SCHOOL_ID
------------------------- ---------- ----------
Panthers University 92022 92022
Blue Rays Middle School 22149 22149
Tables:
schools
SCHOOL_ID SCHOOL_NAME SCHOOL_TYPE
---------- ----------------------------- ------------
92022 Panthers University University
22149 Blue Rays Middle School Middle SchooL
21719 Bull Dogs High School High SchooL
42736 Saint Lucia Grade School Middle SchooL
school_teams
TEAM_ID SPORT_ID SCHOOL_ID TEAM_NAME
---------- ---------- ---------- ----------
1 1 92022 Panthers
2 1 22149 Blue Rays

Use Not exists to do this.
SELECT a.school_name, a.school_id
FROM School a
where not exists (select 1 from Team b where a.school_id = b.school_id)

All those joins (inner, outer, left, right) select only rows that match. You are looking for rows that DON'T match, so they won't suit you.
Try this:
SELECT DISTINCT school_id, school_name FROM school
WHERE school_id not in
(SELECT school_id FROM school_teams)

try:
SELECT DISTINCT a.school_name, a.school_id, b.school_id FROM School a LEFT OUTER JOIN Team b ON a.school_id = b.school_id;

Write this query to generate the required result set. Use Left Join.
SELECT Table1.School_Name, Table1.School_Id FROM Table1 LEFT JOIN Table2 ON Table1.School_Id = Table2.School_Id where Table1.School_Id NOT IN (Select DISTINCT Table2.School_Id From Table2);

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.

How to use 2 instances of the same table

I am wondering how to use 2 instances of the same table in the following example , I know how to do it but I just cant make it work for my task.
I have the following tables :
Agency(id_agency,name)
Space(id_space,address)
Offer(id_agency,id_space)
Task: Find out the address,agency name 1 ,agency name 2 for spaces offered by two different agencies(the combination of 2 agencies is unique).
What I tried:
1)
SELECT ADDRESS,A.NAME,B.NAME
FROM AGENCY A
INNER JOIN OFFER O ON A.ID_AGENCY=O.ID_AGENCY
INNER JOIN SPACE S ON O.ID_SPACE=S.ID_SPACE
WHERE S.ID_SPACE=ANY(SELECT S.ID_SPACE FROM AGENCY B
INNER JOIN OFFER O ON B.ID_AGENCY=O.ID_AGENCY
INNER JOIN SPACE S ON O.ID_SPACE=S.ID_SPACE
);
2)
SELECT ADDRESS
FROM AGENCY A
INNER JOIN OFFER O ON A.ID_AGENCY=O.ID_AGENCY
INNER JOIN SPACE S ON O.ID_SPACE=S.ID_SPACE
INTERSECT
SELECT ADDRESS
FROM AGENCY B
INNER JOIN OFFER O ON B.ID_AGENCY=O.ID_AGENCY
INNER JOIN SPACE S ON O.ID_SPACE=S.ID_SPACE
WHERE A.ID_AGENCY<>B.ID_AGENCY;
In the second example I have no idea how to make it show A.name and b.name, since intersect won't work if I try to add them...
I tried to do this for the last 3 hours , sadly, I guess I can`t do it with the skills I have so far. :(
Thanks in advance
Edit 1: I hope you understand, thats how it should look.
Agency
id_agency name
---------- -------
1 Agency1
2 Agency2
3 Agency3
Space
id_space address
--------- --------
1 address1
2 address2
3 address3
Offer
id_agency id_space
----------- --------
1 1
2 1
3 2
Expected output:
Address Name1 Name2
----------- -------- -------
address1 Agency1 Agency2
To have the results in 1 row, each pair of agencies per row, as you asked for:
select S.address as address, A1.name as agency_1, A2.name as agency_2
from offer O1
join offer O2
on O2.id_space = O1.id_space
and O2.id_agency != O1.id_agency
join space S
on S.id_space = O1.id_space
join agency A1
on A1.id_agency = O1.id_agency
join agency A2
on A2.id_agency = O2.id_agency
;
The "core functionality" here is the join of offer no.1 (O1 alias) to offer no.2 (O2 alias) on equality of id_space but difference of id_agency.
An interesting exercise: To have the results in multiple rows, one agency per row:
select S.address, A.name as agency, X.number_of_agencies_per_space
from (
select id_space, id_agency, count(1) over (partition by id_space) as number_of_agencies_per_space
from offer
) X
join space S
on S.id_space = X.id_space
join agency A
on A.id_agency = X.id_agency
where X.number_of_agencies_per_space > 1
;

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

Query on table joined with itself

Today I have a final Exam. I approved, happily :D but one of the problems is really blowing my mind.
I need help, so I can rest in peace.
THE PROBLEM
We have a table "People"
(PK)id | name | fatherID
---------------------
1 | gon | 2
2 | cesar| 6
3 | luz | 2
4 | maria| 5
5 | diego| 6
6 | john | -
this is only an example of data.
This table has a relation with itself, on table fatherId(FK) with table id(PK)
I need to do a query that show me 2 columns, in one the name of a person, and in the another one, his/her cousin.
Pretty simple until here, right?
The problem is that I have some restrictions
ONLY ANSI allowed. NO T-sql, or another one. Also, ANSI 99 standard, not 2003 or higher
subquerys are not allowed. And the worst:
NO relations repeated.
For example, considering in this example, gon and maria are cousins.
If I show, gon | maria in the results, I can't show maria | gon.
SO, how I can do this?
Is really burning my head.
What I tried?
Well, the big problem was in the last requisite, the repetition of data. Ignoring that, I put this on my exam (knowing is wrong..)
select p3.name as OnePerson, p4.name as Cousin
from
people p1
inner join people p2 on p1.fatherid = p2.fatherid and p1.id != p2.id
inner join people p3 on p1.id = p3.fatherid
inner join people p4 on p1.id = p4.fatherid
of course, this is not solving the last requeriment, and I have a 4 in the test(we pass with 4) but anyway, my head is burning. So please, help me!
Another options explored
one of my friends, that also had the same exam said me
"Well, considering every relation is duplicated, I can use top
count(*) and an order by and get the half correct"
but.. Top is not ANSI!
You can add to your query WHERE p3.id < p4.id. This will eliminate duplicate results like gon | maria and maria | gon.
SELECT T1.id , T2.id FROM
(
SELECT A.id,A.fid FROM family A
WHERE a.fid IN
(
SELECT id FROM family
WHERE fid IN (SELECT id FROM family WHERE fid IS NULL)
)
)T1
JOIN
(
SELECT A.id,A.fid FROM family A
WHERE a.fid IN
(
SELECT id FROM family
WHERE fid IN (SELECT id FROM family WHERE fid IS NULL)
)
)T2
ON t1.fid<>t2.fid
AND t1.id<t2.id
This will give you the results in format you want.
SELECT TAB1.ID,TAB2.ID
FROM
(
SELECT * FROM people T1
WHERE fatherID IN ( SEL T1.ID FROM people T1 INNER JOIN people T2
ON( T1.id=T2.fatherID) WHERE T1.fatherID IS NOT NULL GROUP BY 1) ) TAB1
INNER JOIN
(
SELECT * FROM people T1
WHERE fatherID IN ( SEL T1.ID FROM people T1 INNER JOIN people T2
ON( T1.id=T2.fatherID)WHERE T1.fatherID IS NOT NULL GROUP BY 1) ) TAB2
ON( TAB1.fatherID<>TAB2.fatherID)
GROUP BY 1,2
WHERE TAB1.ID <TAB2.ID;