Nested Query equivalent to inner join - sql

I'm trying to better understand nested queries, and I was wondering what would get me the same result as this:
SELECT PLAYERS.PLAYER_TAG, PLAYERS.POSITION, PLAYERS.TOTAL_KILLS, TEAMS.TEAM_NAMES, TEAMS.GAMES_PLAYED, TEAMS.WINS
FROM PLAYERS
INNER JOIN TEAMS ON TEAMS.TEAM_NAMES = PLAYERS.TEAM
ORDER BY TEAM_NAMES ASC;
but using a nested query instead. Thanks for your help

This is not that kind of query when you need any nested ones (sub-queries) due to lack of any predicates (WHERE clause).

You would not use this and would just use the INNER JOIN query.
However, if a player will only ever be on one team then this query:
SELECT PLAYER_TAG,
POSITION,
TOTAL_KILLS,
( SELECT TEAM_NAMES
FROM teams
WHERE TEAMS.TEAM_NAMES = PLAYERS.TEAM ) AS teams_names,
( SELECT GAMES_PLAYED
FROM teams
WHERE TEAMS.TEAM_NAMES = PLAYERS.TEAM ) AS games_played,
( SELECT WINS
FROM teams
WHERE TEAMS.TEAM_NAMES = PLAYERS.TEAM ) AS wins
FROM PLAYERS
ORDER BY TEAM_NAMES ASC;
(If a player can be on multiple teams then the above query will raise an exception as the nested sub-queries return more than a single row.)
Would be the (inefficient) equivalent of:
SELECT PLAYERS.PLAYER_TAG,
PLAYERS.POSITION,
PLAYERS.TOTAL_KILLS,
TEAMS.TEAM_NAMES,
TEAMS.GAMES_PLAYED,
TEAMS.WINS
FROM PLAYERS
LEFT OUTER JOIN TEAMS
ON TEAMS.TEAM_NAMES = PLAYERS.TEAM
ORDER BY TEAM_NAMES ASC;
(Using a LEFT OUTER JOIN rather than an INNER JOIN.)
If you wanted an INNER JOIN then you can add an EXISTS filter to the outer query's WHERE clause.

Related

How to use coalesce with pivot

Hello I'm trying to figure out to use coalesce with a Pivot so I can replace the NULLS with zeroes instead. Here is what I have:
SELECT * FROM ( SELECT MovieTitle,AwardResultDesc, COALESCE(COUNT(p.AwardResultID),'0') AS T
FROM tblMovie t1
INNER JOIN tblAwardDetail p
ON p.MovieID = t1.MovieID
INNER JOIN tblAwardResult c
ON c.AwardResultID = p.AwardResultID
GROUP BY MovieTitle, AwardResultDesc,p.AwardResultID)
PIVOT
(
max(T) FOR AwardResultDesc IN ('Won' AS "Won",'Nominated' AS "Nominated")
)
ORDER BY MovieTitle;
It seems like my Pivot is ignoring my coalesce for some reason, any suggestions?
By their nature pivot operations involve aggregate functions, so there's no need to pre-aggregate your data, however, you do need to ensure that the data you are pivoting is sufficiently complete. Here outer joining to tblMovie ensures each movie is returned whether it has any award details or not. If you don't want to return counts for movies that neither won nor received nominations, then use an inner join in place of the outer join:
WITH dta AS (
SELECT MovieTitle
, AwardResultDesc
FROM tblAwardResult ar
JOIN tblAwardDetail ad
ON ad.AwardResultID = ar.AwardResultID
RIGHT JOIN tblMovie m
ON m.MovieID = ad.MovieID
)
SELECT *
FROM dta
PIVOT( count(*)
FOR AwardResultDesc IN( 'Won' AS "Won"
, 'Nominated' AS "Nominated" ) )
ORDER BY MovieTitle;

SQL Query using multiple JOINS without sub query

Lets say I have three tables with these columns,
Players - id, name
Events - id, name
Games - first_player_id, second_player_id, event_id.
And I need the players details who are playing in a game which is happening in an event.
And I could write query like,
SELECT players.id, events.id as event_id,
(SELECT name as player_one_name from players where id = games.first_player_id),
(SELECT name as player_two_name from players where id = games.second_player_id),
games.id as game_id
FROM events
INNER JOIN games on events.id = games.event_id
INNER JOIN players on games.first_player_id = players.id;"
Here I am using two sub queries to fetch players name. And it gives correct results. Can this query be optimized? For ex, can I remove any subquery or innerjoin ?
FYI, I use PostgreSQL database.
Thanks.
If you do not want sub queries in your select statement then you must provide a join for each subset. Since your database is set oriented the two INNER JOINS would prove more efficient.
SELECT players.id, events.id as event_id,
player_one_name=player_one.name,
player_tow_name=player_two.name
FROM events
INNER JOIN games on events.id = games.event_id
INNER JOIN players player_one on games.first_player_id = player_one.id
INNER JOIN players player_two on games.second_player_id = player_two.id
You must do a join for each foreign key
SELECT players_a.id, events.id as event_id,
players_a.name as player_one_name,
players_b.name as player_two_name,
games.id as game_id
FROM events
INNER JOIN games on events.id = games.event_id
INNER JOIN players players_a on games.first_player_id = players.id
INNER JOIN players players_b on games.first_player_id = players.id
The currently accepted answer is right about joining the players table twice, but mostly wrong otherwise. This would work:
SELECT e.id AS event_id
,g.id AS game.id
,p1.name AS first_player
,p2.name AS second_player
FROM events e
LEFT JOIN games g ON g.event_id = e.id
LEFT JOIN players p1 ON p1.id = g.first_player_id
LEFT JOIN players p2 ON p2.id = g.second_player_id;
Use LEFT [OUTER] JOIN to cover the cases where an event does not have a game or a game does not have both players (yet).
Use table aliases to simplify your syntax. To join the same table twice you also need at least one table alias.
After attaching an alias to a table in the FROM list, only that alias is visible in your query, not the original name of the table.
Study the manual for details.

Unable to Group on MSAccess SQL multiple search query

please can you help me before I go out of my mind. I've spent a while on this now and resorted to asking you helpful wonderful people. I have a search query:
SELECT Groups.GroupID,
Groups.GroupName,
( SELECT Sum(SiteRates.SiteMonthlySalesValue)
FROM SiteRates
WHERE InvoiceSites.SiteID = SiteRates.SiteID
) AS SumOfSiteRates,
( SELECT Count(InvoiceSites.SiteID)
FROM InvoiceSites
WHERE SiteRates.SiteID = InvoiceSites.SiteID
) AS CountOfSites
FROM (InvoiceSites
INNER JOIN (Groups
INNER JOIN SitesAndGroups
ON Groups.GroupID = SitesAndGroups.GroupID
) ON InvoiceSites.SiteID = SitesAndGroups.SiteID)
INNER JOIN SiteRates
ON InvoiceSites.SiteID = SiteRates.SiteID
GROUP BY Groups.GroupID
With the following table relationship
http://m-ls.co.uk/ExtFiles/SQL-Relationship.jpg
Without the GROUP BY entry I can get a list of the entries I want but it drills the results down by SiteID where instead I want to GROUP BY the GroupID. I know this is possible but lack the expertise to complete this.
Any help would be massively appreciated.
I think all you need to do is add groups.Name to the GROUP BY clause, however I would adopt for a slightly different approach and try to avoid the subqueries if possible. Since you have already joined to all the required tables you can just use normal aggregate functions:
SELECT Groups.GroupID,
Groups.GroupName,
SUM(SiteRates.SiteMonthlySalesValue) AS SumOfSiteRates,
COUNT(InvoiceSites.SiteID) AS CountOfSites
FROM (InvoiceSites
INNER JOIN (Groups
INNER JOIN SitesAndGroups
ON Groups.GroupID = SitesAndGroups.GroupID
) ON InvoiceSites.SiteID = SitesAndGroups.SiteID)
INNER JOIN SiteRates
ON InvoiceSites.SiteID = SiteRates.SiteID
GROUP BY Groups.GroupID, Groups.GroupName;
I think what you are looking for is something like the following:
SELECT Groups.GroupID, Groups.GroupName, SumResults.SiteID, SumResults.SumOfSiteRates, SumResults.CountOfSites
FROM Groups INNER JOIN
(
SELECT SitesAndGroups.SiteID, Sum(SiteRates.SiteMonthlySalesValue) AS SumOfSiteRates, Count(InvoiceSites.SiteID) AS CountOfSites
FROM SitesAndGroups INNER JOIN (InvoiceSites INNER JOIN SiteRates ON InvoiceSites.SiteID = SiteRates.SiteID) ON SitesAndGroups.SiteID = InvoiceSites.SiteID
GROUP BY SitesAndGroups.SiteID
) AS SumResults ON Groups.SiteID = SumResults.SiteID
This query will group your information based on the SiteID like you want. That query is referenced in the from statement linking to the Groups table to pull the group information that you want.

sql select returns duplicate rows because of joins

I am doing a join in select statement and it returns duplicate professional id because of the join.
Select P.ProfessionalID, P.ProfessionalName , S.SpecialtyName
from Professionals P, ProfessionalSpecialtyRelation PR, Specialties S
where
( P.ProfessionalName Like '%arif%' OR P.ProfessionalSurname Like '%%'
)
And P.ProfessionalID = PR.ProfessionalID
AND P.ProfessionalID = POR.ProfessionalID
AND PR.SpecialtyID = S.SpecialtyID
If Prof has two Specialities, it returns that Prof twice. How can I avoid that? what is the best way to do it?
You don't explain what is the speciality you want for your professor having two specialities.
You need to group by professor, and apply an aggregate function on the specialities. Depending on the aggregate function, you will get different results:
SELECT P.ProfessionalID
, P.ProfessionalName
, MAX(S.SpecialtyName)
FROM Professionals P
INNER JOIN ProfessionalSpecialtyRelation PR
ON P.ProfessionalID = PR.ProfessionalID
INNER JOIN Specialties S
ON PR.SpecialtyID = S.SpecialtyID
WHERE P.ProfessionalName Like '%arif%'
OR P.ProfessionalSurname Like '%%'
GROUP BY P.ProfessionalID, P.ProfessionalName
With the MAX function, you will get the maxium of the specialty, in term of string.
Note that you should write your joins explicitly with JOIN clause, instead of writing it implicitly.
If you only want to return one speciality then you can use an aggregate (max/min) function:
Select P.ProfessionalID,
P.ProfessionalName,
max(S.SpecialtyName) SpecialtyName
from Professionals P
inner join ProfessionalSpecialtyRelation PR
on P.ProfessionalID = PR.ProfessionalID
-- and P.ProfessionalID = POR.ProfessionalID You are not joining to a table with POR alias
inner join Specialties S
on PR.SpecialtyID = S.SpecialtyID
where P.ProfessionalName Like '%arif%'
OR P.ProfessionalSurname Like '%%'
group by P.ProfessionalID, P.ProfessionalName;
Or since you are using SQL Server you can also use the row_number() function to return only one row for each professional:
select ProfessionalID,
ProfessionalName,
SpecialtyName
from
(
Select P.ProfessionalID,
P.ProfessionalName,
S.SpecialtyName,
row_number() over(partition by P.ProfessionalID order by S.SpecialtyName) rn
from Professionals P
inner join ProfessionalSpecialtyRelation PR
on P.ProfessionalID = PR.ProfessionalID
-- and P.ProfessionalID = POR.ProfessionalID You are not joining to a table with POR alias
inner join Specialties S
on PR.SpecialtyID = S.SpecialtyID
where P.ProfessionalName Like '%arif%'
OR P.ProfessionalSurname Like '%%'
) d
where rn = 1;
Note: I changed the query to use ANSI JOIN syntax (INNER JOIN) instead of the comma separated list with the joins in the WHERE clause.
remove S from join, and use sub-query to get result with comma.
Use with clause or other ideas.
I hope it well help you.
Best of luck.

Left outer join and group by issue

I wrote a query. this query sum fields from 2 different table. And grouped by main table id field. But second left outer join is not grouped and giving me different results.
SELECT s.*,
f.firma_adi,
sum(sd.fiyat) AS konak,
sum(ss.fiyat) AS sponsor
FROM fuar_sozlesme1 s
INNER JOIN fuar_firma_2012 f
ON ( s.cari = f.cari )
LEFT OUTER JOIN fuar_sozlesme1_detay sd
ON ( sd.sozlesme_id = s.id )
LEFT OUTER JOIN fuar_sozlesme1_sponsor ss
ON ( ss.sozlesme_id = s.id )
GROUP BY s.id
ORDER BY s.id DESC
I know, it is really complicated but I'm stucking on this issue.
My question is: why second left outer join is not correctly sum of field . If I remove second left outer join or first, everything is normal.
The problem is that you have multiple dimensions on your data, and the number of rows is multiplying beyond what you expect. I would suggest that you run the query for one id, without the group by, to see what rows the join is producing.
One way to fix this is by using correlated subqueries:
select s.*, f.firma_adi,
(select SUM(sd.fiyat)
from fuar_sozlesme1_detay fd
where sd.sozlesme_id = s.id
) as konak,
(select SUM(ss.fiyat)
from fuar_sozlesme1_sponsor ss
where (ss.sozlesme_id = s.id)
) as sponsor
from fuar_sozlesme1 s inner join
fuar_firma_2012 f
on (s.cari = f.cari)
order by s.id DESC
By the way, you appear to by using MySQL (because your query is not parsable in any other dialect). You should tag your questions with the version of the database you are using.