How to select SQL results based on multiple tables - sql

I need to select results from one table based on certain matching values in a couple of other tables. I have the following tables:
person: id, firstname, lastname
team: id, teamname
player: id, person_id(FK), team_id(FK)
coach: id, person_id(FK), team_id(FK)
I need to return all the coaches and players names for each team. I've only ever used inner joins, and it doesn't seem like I can use those here, so any idea how to do this?

This will give you the coach:
SELECT team.Teamname, person.Firstname, person.Lastname
FROM person
JOIN coach ON person.id = coach.person_id
JOIN team ON coach.team_id = team.id
And this will give you the players:
SELECT team.Teamname, person.Firstname, person.Lastname
FROM person
JOIN player ON person.id = player.person_id
JOIN team ON player.team_id = team.id
So, the non-elegant, simple answer is to just toss it all together with UNION.

Just use an OR in the join to Team
SELECT
P.firstname,
P.lastname,
T.teamname
FROM
person p id
LEFT JOIN player pl
ON p.id = pl.person_id
LEFT JOIN coach c
ON p.id = c.person_id
LEFT JOIN team t
ON pl.team_id = t.id
or.c.team_id = t.id
Or if you perfer if and your database has COALESCE
LEFT JOIN team t
ON COALESCE(pl.team_id,c.team_id) = t.id

Related

Fetching columns, 4 tables

I’ve ran in to some problems with the following SQL assignment. I’m to retrieve the ID, firstname and lastname of any member who is registered in section that contains the word ‘xyz’.
So far I’ve managed the following:
SELECT m.id, p.firstname, p.lastname FROM member m
INNER JOIN person p ON m.id = p.id
WHERE m.id IN (SELECT id FROM membersection);
How do I go forward from here? I have no idea how to retrieve the sectionid from the membersection table then fetch the section name from the section id using that ID so I can check if the section name contains the previously stated word.
member:
id
member_number
registration_date
membersection:
memberid
sectionid
person:
id
firstname
lastname
section:
id
name
Just keep joining. And in the end use LIKE to check if section.name contains 'xyz'.
SELECT m.id,
p.firstname,
p.lastname
FROM member m
INNER JOIN person p
ON p.id = m.id
INNER JOIN membersection ms
ON ms.memberid = m.id
INNER JOIN section s
ON s.id = ms.sectionid
WHERE s.name LIKE '%xyz%';
There is some ambiguity in your question with regards to how your data are structured; what are the primary and foreign keys?
But, making some assumptions, you're almost there, you can chain multiple join statements together:
select
m.id,
p.firstname,
p.lastname
from
member m
inner join person p on
m.id = p.id
inner join membersection ms on
m.id = ms.memberid
inner join section s on
ms.sectionid = s.id
where
s.name like '%xyz%'
It's not super obvious what's going on with your Data Relationships, but this would be the basic route you might want to take (LEFT JOIN as I do not know the relationship):
SELECT m.id, p.firstname, p.lastname, ms.sectionid
FROM member m
INNER JOIN person p ON m.id = p.id
LEFT JOIN section s ON m.id = s.id
LEFT JOIN membersection ms ON m.id = ms.memberid
WHERE s.name = 'xyz'

SQL query find records that not persists in other tables

I need to print all persons which are not students and not teachers. I have three tables. Oracle database. Code so far:
SELECT PersonID, FirstName, LastName, Gender, DateOfBirth
FROM PERSON
INNER JOIN STUDENT S ON PERSON.PersonID = S.StudentID
INNER JOIN TEACHER T ON PERSON.PersonID = T.TeacherID
WHERE PERSON.PersonID != S.StudentID
AND PERSON.PersonID != T.TeacherID;
I guess my query is wrong because it returns 0 results. Do you have any idea what must I change?
" my query is wrong because it returns 0 results"
Inner joins return records when there is a match. You're trying to find PERSON records which join to neither STUDENT nor TEACHER. So, change your query to use outer joins:
SELECT PersonID, FirstName, LastName, Gender, DateOfBirth
FROM PERSON
LEFT OUTER JOIN STUDENT S ON PERSON.PersonID = S.StudentID
LEFT OUTER JOIN TEACHER T ON PERSON.PersonID = T.TeacherID
WHERE S.StudentID is null
AND T.TeacherID is null;
This is an anti-join: it returns records from PERSON which don't match records in STUDENT and TEACHER.
Use not exists:
select p.*
from person p
where not exists (select 1 from teacher t where t.teacherid = p.personid) and
not exists (select 1 from students s where s.studentid = p.personid);
Although you can write this query with left join, I think the version using not exists is almost a direct translation of the question, making it easier to understand.
In Oracle, you can also write this using minus -- if you want only the id:
select personid
from person
minus
select teacherid
from teacher
minus
select studentid
from student;
--Try this with Left Outer Join...
SELECT
P.PersonID,
P.FirstName,
P.LastName,
P.Gender,
P.DateOfBirth
FROM PERSON P
LEFT OUTER JOIN STUDENT S ON P.PersonID = S.StudentID
LEFT OUTER JOIN TEACHER T ON P.PersonID = T.TeacherID
WHERE S.PersonID is null and T.PersonID is null

SQL Query Help - Multiple JOINS

having trouble with this SQL query. Here's the situation:
I have three tables structured as follows:
Events -> fields ID and Name,
Players -> fields ID and Name,
Matches -> fields ID, EventID, Player1ID, Player2ID
I would like to perform a query that shows me the Matches Table, but replaces the EventID with the Event.Name, the Player1ID with the Players.Name and the Player2ID with the Players.Name.
It is easy for me to get one Player and the Event using this:
SELECT
Players.Name as Player1, Events.Name
FROM
(Matches
INNER JOIN
Events ON (Matches.EventID=Events.ID))
INNER JOIN
Players ON (Matches.Player1ID = Player.ID) ;
But, how do I get the Player2's name?
Add a second JOIN to the Players table:
SELECT
Players.Name as Player1, Events.Name,
p2.Name as Player2
FROM
Matches
INNER JOIN
Events ON Matches.EventID = Events.ID
INNER JOIN
Players ON Matches.Player1ID = Player.ID
INNER JOIN
Players p2 ON Matches.Player2ID = p2.ID;
You can do this by joining the tables together. The trick is that you have to include the Players table twice. This is a case where you need table aliases to distinguish between these two references to the table in the from clause:
select m.matchid, e.name as event_name, p1.name as player1_name, p2.name as player2_name
from matches m join
events e
on m.eventid = e.id join
players p1
on m.player1 = p1.id join
players p2
on m.player2 = p2.id;
I also added table aliases for the other tables, which makes the query easier to read.
SELECT p1.Name, p2.Name, Events.Name
FROM Matches
INNER JOIN Events ON (Matches.EventID=Events.ID))
INNER JOIN Players p1 ON (Matches.Player1ID = p1.ID)
INNER JOIN Players p2 ON (Matches.Player2ID = p2.ID)
You need to join the query again with the Players table on the Player2ID field. So change your query to:
SELECT one.Name as Player1, two.Name as Player2, Events.Name
FROM
Matches INNER JOIN
Events ON Matches.EventID=Events.ID INNER JOIN
Players one ON Matches.Player1ID = one.ID INNER JOIN
Players two ON Matches.Player1ID = two.ID

How to write this query to display a COUNT with other fields

I have following two tables:
Person {PersonId, FirstName, LastName,Age .... }
Photo {PhotoId,PersonId, Size, Path}
Obviously, PersonId in the Photo table is an FK referencing the Person table.
I want to write a query to display all the fields of a Person , along with the number of photos he/she has in the Photo table.
A row of the result will looks like
24|Ryan|Smith|28|6
How to write such query in tsql?
Thanks,
You need a subquery in order to avoid having to repeat all the columns from Person in your group by clause.
SELECT
p.PersonId,
p.FirstName,
p.LastName,
p.Age,
coalesce(ph.PhotoCount, 0) as Photocount
FROM
Person p
LEFT OUTER JOIN
(SELECT PersonId,
COUNT(PhotoId) as PhotoCount
FROM Photo
GROUP BY PersonId) ph
ON p.PersonId = ph.PersonId
SELECT
p.PersonId,
p.FirstName,
p.LastName,
p.Age,
CASE WHEN
t.ThePhotoCount IS NULL THEN 0 ELSE t.ThePhotoCount END AS TheCount
--the above line could also use COALESCE
FROM
Person p
LEFT JOIN
(SELECT
PersonId,
COUNT(*) As ThePhotoCount
FROM
Photo
GROUP BY PersonId) t
ON t.PersonId = p.PersonID
SELECT P.PersonId, FirstName, LastName,Age, COUNT(PhotoId) AS Num
FROM Person P
LEFT OUTER JOIN PHOTO PH ON P.PersonId = PH.PersonId
GROUP BY P.PersonId, FirstName, LastName,Age
select Person.*, count(PhotoId) from Person left join Photo on Person.PersonId = Photo.PersonId
IMO GROUP BY should be the solution, something like this works for me even with other table joins:
SELECT meetings.id, meetings.location, meetings.date, COUNT( users.id ) AS attendees
FROM `meetings`
LEFT JOIN users ON meetings.id = users.meeting_id
WHERE meetings.moderator_id = 'XXX'
GROUP BY meetings.id

how to combine 2 or more bridge tables in a single query

i have the following tables:
Table: People (id, first, last, age, phone, etc . .)
Table: Roles (id, name)
Table: Skills (id, name)
Table: People_Roles (id, personID^, roleID^)
Table: People_Skills (id, personID^, skillID^)
^ = foreign key
I basically want a query that gives me the full result set of all people and their roles and there skills.
Person.First, Person.Last, Roles.Name, Skills.Name
SELECT p.first, p.last, r.name, s.name
FROM People p
LEFT JOIN People_Roles pr
ON pr.personID = p.id
INNER JOIN Roles r
ON pr.roleID = r.id
LEFT JOIN People_Skills ps
ON ps.personID = p.id
INNER JOIN Skills s
ON ps.skillID = s.id
This query will select you all the people, even those without Roles or Skills assigned.
This query will work:
SELECT Person.First, Person.Last, Roles.Name, Skills.Name
FROM People
LEFT JOIN People_Skills
ON People.id = People_Skills.personID
INNER JOIN Skills
ON People_Skills.skillID = Skills.id
LEFT JOIN People_Roles
ON People.id = People_Roles.personID
INNER JOIN Roles
ON People_Roles.roleID = Skills.id
By the way, why your "bridge" tables have their own ID. I would just use a compound key made of PersonID and the corresponding foreign key (skillsID or rolesID) to ensure that every pair can only be made once.