Multiple left joins on multiple tables in one query
This kind of query should work - after rewriting with explicit JOIN
syntax:
SELECT something
FROM master parent
JOIN master child ON child.parent_id = parent.id
LEFT JOIN second parentdata ON parentdata.id = parent.secondary_id
LEFT JOIN second childdata ON childdata.id = child.secondary_id
WHERE parent.parent_id = 'rootID';
The tripping wire here is that an explicit JOIN
binds before a comma (,
), which is otherwise equivalent to CROSS JOIN
. The manual here:
In any case
JOIN
binds more tightly than the commas separatingFROM
-list items.
After rewriting the first, all joins are applied left-to-right (logically - Postgres is free to rearrange tables in the query plan otherwise) and it works.
Just to make my point, this would work, too:
SELECT something
FROM master parent
LEFT JOIN second parentdata ON parentdata.id = parent.secondary_id
, master child
LEFT JOIN second childdata ON childdata.id = child.secondary_id
WHERE child.parent_id = parent.id
AND parent.parent_id = 'rootID';
But explicit JOIN
syntax is generally clearer.
And be aware that multiple (LEFT
) JOIN
can multiply rows:
- Two SQL LEFT JOINS produce incorrect result
Multiple LEFT JOIN in multiple tables
When looking for aggregates from different tables, you should always aggregate before joining:
SELECT
s.*,
mul.multimedia,
cat.categories
FROM sections s
LEFT JOIN
(
SELECT
sm.section_id,
GROUP_CONCAT(CONCAT_WS(':', m.type, m.id, m.filename) SEPARATOR ',') AS multimedia
FROM sections_multimedia sm
JOIN multimedia m ON sm.multimedia_id = m.id
GROUP BY sm.section_id
) mul ON s.id = mul.section_id
LEFT JOIN
(
SELECT
sc.section_id,
GROUP_CONCAT(CONCAT_WS(':', c.id) SEPARATOR ',') AS categories
FROM sections_categories sc
JOIN categories c ON sc.category_id = c.id
GROUP BY sc.section_id
) cat ON s.id = cat.section_id;
Multiple LEFT OUTER JOIN on multiple tables
The join
on D
is an inner join, the rest are left outer joins:
SELECT *
FROM TABLEA A JOIN
TABLED D
ON D.Z = A.Z LEFT JOIN
TABLEB B
ON A.X = B.X LEFT JOIN
TABLEC C
ON B.Y = C.Y
WHERE MY_COL = @col_val;
I always start chains of joins with inner joins followed by the left outer join
. I never use right join
, and full join
rather rarely. The inner joins define the rows in the result set, so they come first.
SQL Multiple Left Joins on Same Parent Key
You would use union all
:
select a.id, a.name, b.title, a.amount
from TableA a Left Join
TableB b
on a.ID = b.ID
union all
Select a.id, a.name, b.title, a.amount
from TableA a Left Join
TableC c
on a.ID = c.ID and a.name = c.name
Multiple LEFT JOINS for the same column
If you're LEFT
joining the same table twice, could you just join on it once and add an OR
to your join and use both conditions?
SELECT a.*, b.Game_Code
FROM [NCAAF].[dbo].[MasterSheet] a
LEFT JOIN (SELECT DISTINCT Game_Code, Date, Visit_Team_Code, Home_Team_Code
from dbo.game2018) b
ON a.Date = b.Date and
((a.[Team Code] = b.Visit_Team_Code and a.[Opponent Code] = b.Home_Team_Code)
OR
(a.[Team Code] = b.Home_Team_Code and a.[Opponent Code] = b.Visit_Team_Code))
Combine multiple left joins in 1 query
This should bring back the rows for both tables B and C for each row of table A:
SELECT A.BIZ_GROUP,
A.ORDER_ID,
A.STATION,
A.TC_DATE,
A.WANT_DATE,
A.TIME_SLOT,
A.JOB_CODE,
A.[ADDRESS],
A.CITY,
A.TECH_ID,
A.PREMISE,
ISNULL(B.LAST_ARRIVED, A.LAST_ARRIVE) AS ARRIVED,
A.ORDER_CLOSED,
A.COMP_STATUS,
A.WORK_STATUS,
A.REMARKS,
A.CORRECTION,
C.*
FROM MET_timecommit A
LEFT JOIN(SELECT premise,
TC_DATE,
TECH_ID,
MIN(last_arrive) AS LAST_ARRIVED
FROM MET_timecommit
WHERE PREMISE IS NOT NULL
GROUP BY premise,
TC_DATE,
TECH_ID) B ON B.TC_DATE = A.TC_DATE
AND B.PREMISE = A.PREMISE
LEFT JOIN (SELECT ORDER_ID,
created,
host_creation,
went_to
FROM workload
WHERE went_to >= getdate()-365) C ON C.went_to=A.MET_timecommit.TC_DATE
AND C.order_id=A.MET_timecommit.order_id
Avoiding multiple left joins of a single table for multiple columns
You can also use aggregation:
select t1.*, t2.code_01, t2.code_02, t2.code_03
from table1 t1 left join table2
(select t2.special_id,
max(case when t2.dependent_value = '01' then t2.value_wanted end) as code_01,
max(case when t2.dependent_value = '02' then t2.value_wanted end) as code_02,
max(case when t2.dependent_value = '03' then t2.value_wanted end) as code_03
from table2 t2
group by t2.special_id
) t2
on t2.special_id = t1.special_id ;
Instead of a new join, you need to add a new condition to the subquery. Whether this is faster or slower . . . well that depends.
Related Topics
How to Select Using with Recursive Clause
How to Concatenate Text from Multiple Rows into a Single Text String in Oracle Server
How to Perform a Replace on Varbinary Data in SQL
Sql: When It Comes to Not in and Not Equal To, Which Is More Efficient and Why
Selecting Distinct Combinations
Return Boolean Value on SQL Select Statement
Add Missing Data from Previous Month or Year Cumulatively
Select Something That Has More/Less Than X Character
Any Detailed and Specific Reasons for Why Mongodb Is Much Faster Than SQL Dbs
Query Grants for a Table in Postgres
Delete Rows with Foreign Key in Postgresql
Generate Insert Script for Selected Records