FULL OUTER JOIN value condition
-
17-04-2021 - |
Question
I need to add value condition to the FULL OUTER JOIN.
I.e. I'm triyng to do this:
SELECT *
FROM Table1
FULL OUTER JOIN Table2 ON Table1.Field1 = Table2.Field1 AND Table2.Field2 > 5
But this script doesn't work. Actually it looks like the condition (Table2.Field2 > 5) was never applied at all.
The same issue appears for the RIGHT OUTER JOIN, so I think the reason is that when there is RIGHT or FULL join no value conditions applied to the right table in join.
Why is this happening? Is there a conceptual explanation of such behaviour?
And of course the main question is how to solve this issue.
Is there a way to solve this without using subqueries?
SELECT *
FROM Table1
FULL OUTER JOIN (SELECT * FROM Table2 WHERE Table2.Field2 > 5) AS t2 ON Table1.Field1 = t2.Field1
Solution
Pretty convulated but no subqueries
SELECT Table1.*
, CASE WHEN Table2.Field2 > 5 THEN Table2.Field1 ELSE NULL END
, CASE WHEN Table2.Field2 > 5 THEN Table2.Field2 ELSE NULL END
FROM Table1
FULL OUTER JOIN Table2 ON Table1.Field1 = Table2.Field1
WHERE COALESCE(Table2.Field2, 6) > 5
OR Table1.Field1 = Table2.Field1
Test script
;WITH Table1 AS (
SELECT * FROM (VALUES
(1, 1)
, (2, 2)
, (5, 5)
, (6, 6)
) AS Table1 (Field1, Field2)
)
, Table2 AS (
SELECT * FROM (VALUES
(1, 1)
, (3, 3)
, (4, 4)
, (5, 5)
, (7, 7)
) AS Table2 (Field1, Field2)
)
SELECT Table1.*
, CASE WHEN Table2.Field2 > 5 THEN Table2.Field1 ELSE NULL END
, CASE WHEN Table2.Field2 > 5 THEN Table2.Field2 ELSE NULL END
FROM Table1
FULL OUTER JOIN Table2 ON Table1.Field1 = Table2.Field1
WHERE COALESCE(Table2.Field2, 6) > 5
OR Table1.Field1 = Table2.Field1
Results
Field1 Field2 Field1 Field2
1 1 NULL NULL
5 5 NULL NULL
NULL NULL 7 7
6 6 NULL NULL
1 1 NULL NULL
2 2 NULL NULL
OTHER TIPS
What you want might be reformulated as:
SELECT *
FROM Table1
LEFT JOIN Table2 ON Table1.Field1 = Table2.Field1 AND Table2.Field2 > 5
UNION ALL
SELECT *
FROM Table1
RIGHT JOIN Table2 ON Table1.Field1 = Table2.Field1
WHERE Table2.Field2 > 5
AND Table1.Field1 IS NULL
but using subquery as suggested by yourself is IMO the best option.
This used to confuse me. Now I get it! The conditions after "on" (in your case:Table1.Field1 = Table2.Field1 AND Table2.Field2 > 5 ) tells the join operator which rows from the two tables are joined. This means when and only when row1 from table1 and row2 from tables satisfy both row1.field1 = row2.field2 and row2.field2 > 5 that row1 and row2 are joined. The rest rows are not joined.
So in full outer join, the result set would then be joined rows, non-joined rows from table1 and non-joined rows from table2. In right join, the result set would be joined rows, non-joined rows from table2. In either case, rows from table 2 with field2 <= 5 will be among the result sets of non-joined rows from table2.
This is why "Table2.Field2 > 5" is working properly in left join but not that "properly" in right or full join, but the value conditions do be doing their jobs right.