In SQL, What's the difference a ON condition following a Join vs at the end of multiple JOINS - sql

I have been having a hard time googling an answer for this, but....
can someone explain to me the difference between putting the ON condition of a JOIN with the the JOIN itself vs putting the ON at the end of all the other JOINs.
here is an example http://sqlfiddle.com/#!3/e0a0f/3
CREATE TABLE TableA (Email VARCHAR(100), SomeNameA VARCHAR(100))
CREATE TABLE Tableb (Email VARCHAR(100), SomeNameB VARCHAR(100))
CREATE TABLE Tablec (Email VARCHAR(100), SomeNameC VARCHAR(100))
INSERT INTO TableA SELECT 'joe#test.com', 'JoeA'
INSERT INTO TableA SELECT 'jan#test.com', 'JaneA'
INSERT INTO TableA SELECT 'dave#test.com', 'DaveA'
INSERT INTO TableB SELECT 'joe#test.com', 'JoeB'
INSERT INTO TableB SELECT 'dave#test.com', 'DaveB'
INSERT INTO TableC SELECT 'joe#test.com', 'JoeC'
INSERT INTO TableC SELECT 'dave#test.com', 'DaveC'
SELECT TOP 2 a.*,
b.*,
c.*
FROM TableA a
LEFT OUTER JOIN TableB b
ON a.email = b.email
INNER JOIN TableC c
ON c.Email = b.email;
SELECT TOP 2 a.*,
b.*,
c.*
FROM TableA a
LEFT OUTER JOIN TableB b
INNER JOIN TableC c
ON c.Email = b.email
ON a.email = b.email;
I don't understand why these two SELECT statements produce different results.

What matters is orders of joins. Treat your expressions as if every join produced temporary "virtual" table.
So when you write
FROM TableA a
LEFT OUTER JOIN TableB b ON a.email = b.email
INNER JOIN TableC c ON c.Email = b.email ;
then order is as follows:
TableA is left joined to TableB producing temporary relation V1
V1 is inner joined to TableC.
Meanhwile when you write:
FROM TableA a
LEFT OUTER JOIN TableB b
INNER JOIN TableC c ON c.Email = b.email ON a.email = b.email;
then order is as follows:
TableB is inner joined to TableC producing temporary relation V1.
TableA is left joined to V1.
Thus results are different. It is generally recommended to use parenthesis in such situations to improve readability of the query:
FROM TableA a
LEFT OUTER JOIN
(TableB b INNER JOIN TableC c ON c.Email = b.email)
ON a.email = b.email;

In your second example, the part ON a.email = b.email belongs to the LEFT JOIN.
If written like this, it means the following:
INNER JOIN TableC with TableB and LEFT OUTER JOIN the result with TableA.
The result will be all rows from TableA joined with those rows from TableB that also have an entry in TableC.
The first example means the following:
LEFT OUTER JOIN TableB with TableA and INNER JOIN TableC with the result. This is equivalent to using an INNER JOIN for TableB.
Explanation: When you LEFT OUTER JOIN TableA with TableB you will get all rows from TableA and for matching rows in TableB you will get that data, too. In your result set you will have rows with b.email = NULL and this will now be INNER JOINed with TableC. As long as there is no entry in TableC with email = NULL you will get the results you observed.

Related

Conditional join in SQL Server dependent on other table values

I need make a decision which table should be use in join statement depend on values in another table
I tried using CASE and COALESCE but can't achieve any success.
TableA has A and B and C and many other columns
TableB has ID and NAME columns
TableC has ID and NAME columns
My select statement is;
Select A.D, A.E, A.F From TableA A
If A.E = 1 then the following join should be used
left outer join TableB B ON A.B = B.ID
and B.NAME should be returned in the select statement
If A.E = 2 then the following join should be used
left outer join TableC C ON A.B = C.ID
and C.NAME should be returned in the select statement
Just add your conditions to the joins, and then use a case statement to pull the correct field to your result set e.g.
select A.D, A.E, A.F
, case when B.[Name] is not null then B.[Name] else C.[Name] end [Name]
from TableA A
left outer join TableB B ON A.B = B.ID and A.E = 1
left outer join TableC C ON A.B = C.ID and A.E = 2
Join tablea with the union of tableb with an extra column with value 1 and tablec with an extra column with value 2 and apply the conditions in the ON clause:
select
a.D, a.E, a.F, u.NAME
from tablea a
left join (
select *, 1 col from tableb
union all
select *, 2 col from tablec
) u on a.B = u.id and a.E = u.col

issue in sql join query formation

I have two tables Say A and B. A is master table and B is child table, from which I need values as below.
select A.Id, A.Name, B.Path from A,B where A.Id=B.Id
Now, I want to add column of 3rd table which is child of table 'B', say C i.e. C.File.
The value of C.File will be null if C.SubId=B.SubId is false else will return value when condition becomes true.
This is the exact definition of a left join:
SELECT a.id, b.name, b.path, c.file
FROM a
JOIN b ON a.id = b.id
LEFT JOIN c ON b.subid = c.subid
You need to LEFT JOIN your third table from what I can gather.
SELECT A.Id, A.Name, B.Path, C.file
FROM tableA a
INNER JOIN tableB b ON a.id = b.id
LEFT JOIN tableC c ON b.subid = c.subid
Simply Join all the three tables using INNER JOIN
select A.Id, A.Name, B.Path ,C.File
FROM A
INNER JOIN B
ON A.Id=B.Id
INNER JOIN C
ON C.SubId=B.SubId

Left Join With Regular Joins and Results

Question with left join. I am trying to LEFT JOIN a table that requires other tables to be joined on the initial left joined table. So..
SELECT * FROM tableA
LEFT JOIN tableB
ON tableB.id=tableA.id
JOIN tableC
ON tableC.id=tableB.id
The problem is if I don't left join table C I get no results, and if do left join I get too many results.
What kind of joins should I be using where if tableB join is null, tableC joins will also be null?
What about a subquery ?
SELECT * FROM tableA
LEFT JOIN (SELECT tableB.id FROM tableB
JOIN tableC
ON tableC.id=tableB.id) tableZ
ON tableZ.id=tableA.id
I don't left join table C I get no results, and if do left join I get
too many results
You need to determine what is your driving table and data. In this case, it seems like table A is the driving table and the join from B to C also could be a left join, meaning data from C could be returned even if no matching exists in B.
SELECT * FROM tableA
LEFT JOIN tableB
ON tableB.id=tableA.id
LEFT JOIN tableC
ON tableC.id=tableB.id
if do left join I get too many results
Can you post some sample data to show what you mean by this?
I think you might want this logic:
SELECT *
FROM tableA LEFT JOIN
(tableB JOIN
tableC
ON tableC.id = tableB.id
)
ON tableB.id = tableA.id ;
Normally, with LEFT JOIN you want to chain them, but there are some exceptions.

SQL full join priority

Say you have 3 tables (tableA, tableB, tableC), each with an ID column and a Value column. Some of the tables' IDs match but some don't.
If you do:
SELECT tableA.ID FROM tableA
FULL JOIN tableB ON (tableA.ID = tableB.ID)
FULL JOIN tableC ON (tableA.ID = tableC.ID)
Is this different from:
SELECT tableA.ID FROM tableA
FULL JOIN tableB ON (tableA.ID = tableB.ID)
FULL JOIN tableC ON (tableB.ID = tableC.ID)
Or:
SELECT Y.ID FROM
(SELECT tableA.ID FROM tableA
FULL JOIN tableB ON (tableA.ID = tableB.ID)) X
FULL JOIN tableC ON (X.ID = tableC.ID)) Y
??? Someone please explain if there is a difference. Thanks.
[Oracle SQL Developer version 4.02.15.21]
For starters, here are all 3 statements, syntactically cleaned up:
SELECT COALESCE(a.ID,b.ID,c.ID)
FROM tableA a
FULL JOIN tableB b ON a.ID = b.ID
FULL JOIN tableC c ON a.ID = c.ID
SELECT COALESCE(a.ID,b.ID,c.ID)
FROM tableA a
FULL JOIN tableB b ON a.ID = b.ID
FULL JOIN tableC c ON b.ID = c.ID
SELECT COALESCE(X.ID,c.ID)
FROM
( SELECT COALESCE(a.ID ,b.ID) ID
FROM tableA a
FULL JOIN tableB b ON a.ID = b.ID) X
FULL JOIN tableC c ON X.ID = c.ID
Surprisingly, the syntax of the first statement produces duplicate values, but statements 2 and 3 work as advertised.
Edit: Upon further testing, statements 1 and 2 are prone to duplicates, depending on which tables overlap. Statement 3 seems to be the only solid approach.
SQLFiddle

Difficulty with sql query

I have the following tables:
TableA (id, tableB_id, tableC_id)
TableB (id, expirationDate)
TableC (id, expirationDate)
I want to retrieve all the results from TableA ordered by tableB.expirationDate and tableC.expirationDate. How can I do this?
select ta.*
from TableA ta
inner join TableB tb on ta.tableB_id = tb.id
inner join TableC tc on ta.tableC_id = tc.id
order by tb.expirationDate, tc.expirationDate
Update:
If you are not getting all the records, then you'll need to use a left outer join:
select ta.*
from TableA ta
left outer join TableB tb on ta.tableB_id = tb.id
left outer join TableC tc on ta.tableC_id = tc.id
order by tb.expirationDate, tc.expirationDate
If the result set is empty with the other suggestions, are you sure the data in the tables is actually correctly correlated to each other?
Can you post some sample rows for each table?
Have you tried:
SELECT a.* FROM TableA a
INNER JOIN TableB b on b.id = a.tableB_id
INNER JOIN TableC c on c.id = a.tableC_id
ORDER BY b.expirationDate, c.expirationDatetableB_id