Is left join commutative? What are its properties? - mysql

Assume tables TableA TableB TableC and TableD:
Is the following query:
TableA INNER JOIN TableB LEFT JOIN TableC LEFT JOIN TableD
(all joined to an id column) equivalent to:
TableA INNER JOIN TableB
INNER JOIN TableC
LEFT JOIN TableD
UNION
TableA INNER JOIN TableB
LEFT JOIN TableC ON TableB.c_id IS NULL
LEFT JOIN TableD
?
Note:
Or instead of union just do
TableA INNER JOIN TableB
INNER JOIN TableC
LEFT JOIN TableD
And then
TableA INNER JOIN TableB
LEFT JOIN TableC ON TableB.c_id IS NULL
LEFT JOIN TableD
and then combine the results
Update
Is
(A INNER JOIN B) LEFT JOIN C LEFT JOIN D
the same as:
A INNER JOIN (B LEFT JOIN C) LEFT JOIN D
?

Wikipedia:
"In mathematics, a binary operation is commutative if changing the order of the operands does not change the result. It is a fundamental property of many binary operations, and many mathematical proofs depend on it."
Answer:
no, a left join is not commutative. And inner join is.
But that's not really what you are asking.
Is the following query:
TableA INNER JOIN TableB LEFT JOIN TableC LEFT JOIN TableD
(all joined to an id column) equivalent to:
TableA INNER JOIN TableB
INNER JOIN TableC
LEFT JOIN TableD
UNION
TableA INNER JOIN TableB
LEFT JOIN TableC ON TableB.c_id IS NULL
LEFT JOIN TableD
Answer:
Also no. Unions and joins don't really accomplish the same thing, generally speaking. In some case you may be able to write them equivalently, but I don't think so general pseudo sql you are showing. The ON constitution seemslike it should not work (maybe something about which I do not know in MySQL?)
Here is a simplified set of queries that I do think would be equivalent.
SELECT *
FROM TableA a
LEFT JOIN
TableB b ON a.id = b.id_a
SELECT *
FROM TableA a
INNER JOIN
TableB b ON a.id = b.id_a
UNION
SELECT *
FROM TableA a
LEFT JOIN
TableB b ON a.id = b.id_a
WHERE TableB.id IS NULL
Edit 2:
Here's another example that is closer to your but in essence the same.
SELECT *
FROM TableA a
INNER JOIN TableB b ON a.id = b.id_a
LEFT JOIN TableC c ON b.id = c.id_b
is the same as
SELECT *
FROM TableA a
INNER JOIN TableB b ON a.id = b.id_a
INNER JOIN TableC c ON b.id = c.id_b
UNION
SELECT *
FROM TableA a
INNER JOIN TableB b ON a.id = b.id_a
LEFT JOIN TableC c ON b.id = c.id_b
WHERE TableC.id IS NULL
But I still don't think I'm answering your real question.

Related

MySQL How to do a 3 table join

I'm trying to perform a 3 table join on MySQL in order to achieve something like the diagram below.
The main problem I'm having is that I only want to work with the records of table A which has 100 records so if there are no relationships for the right tables I would like to see a null.
This all works fine when only table A and B are involved but when I try to do the third join with C I'm getting more than the original 100 records, I'm getting 130 which I believe is because is adding the records that match B-C with duplicate data from table A.
What am I missing?
This is the SQL I currently have that returns correctly 100 records
SELECT count(A.id)
FROM tableA A
LEFT JOIN TableB B ON B.id = A.b_id
This is what I'm trying to do that is returning more than the original 100 records for Table A.
SELECT count(A.id)
FROM tableA A
LEFT JOIN TableB B ON B.id = A.b_id
LEFT JOIN TableC C ON C.id = B.c_id
This could be resolved by a JOIN to a subquery rather than a table.
If you had unique Ids to join to, it would simply be like you've tried already (arbitrary example):
SELECT * from table1 t1
LEFT JOIN table2 t2 on t2.id = t1.id
LEFT JOIN table3 t3 on t3.id = t2.id
If, however the id field in table3 wasn't unique, you'd get multiple rows for each duplicate. You could resolve this by:
SELECT * from table1 t1
LEFT JOIN table2 t2 on t2.id = t1.id
LEFT JOIN (SELECT * FROM table3 GROUP BY id) t3 on t3.id = t2.id
So, using your example (assuming only the third join has duplicates), something like:
SELECT count(A.id)
FROM tableA A
LEFT JOIN TableB B ON B.id = A.b_id
LEFT JOIN (SELECT * FROM TableC GROUP BY id) C ON C.id = B.c_id
...should do the trick. This is down to assumption of your table and data structure, so you might want to make the asterisk more explicit.
SELECT count(distinct A.id)
FROM tableA A
LEFT JOIN TableB B ON B.id = A.b_id
LEFT JOIN TableC C ON C.id = B.c_id

Table identifiers with LEFT JOIN

How does one join say, on tableD.id = tableC.id AND tableD.id = tableE.id? both tableD and E may have 0 rows and I need to count them ie. SELECT COUNT(E.id). The problem is I don't know where to declare the table identifiers.
I've tried:
FROM tableB B, tableD D, tableE E ...
LEFT JOIN (tableC C, tableD D) ON ...
SELECT B.*, COUNT(C.id) AS cCount
FROM tableB B
LEFT JOIN (tableC C)
ON (B.id = C.id)
GROUP BY B.id
It is a little difficult to tell from your question what you're looking for, but I believe this is it:
SELECT B.*, COUNT(C.id) AS cCount
FROM tableB AS B
LEFT JOIN tableC AS C ON B.id = C.id
LEFT JOIN tableD AS D ON C.Id = D.Id
LEFT JOIN tableE AS E ON D.Id = E.Id
GROUP BY B.id

Help with JOINs in query

SELECT * FROM
Table_A
LEFT JOIN Table_B
ON (Table_A.A_ID = Table_B.A_ID)
INNER JOIN Table_C ON (Table_C.C_ID = Table_B.C_ID)
WHERE Table_A.ID = 3
This returns 0 rows, currently.
How can I set this up so I always get Table_A, even if there is no row for Table_B or Table_C. I still want to maintain the INNER JOIN between Table_B and Table_C, so that I will never get a B without a C.
Sub query the Table B and Table C. e.g.
SELECT *
FROM Table_A
LEFT JOIN
(SELECT *
FROM Table_B
INNER JOIN Table_C ON (Table_C.C_ID = Table_B.C_ID)
) B_AND_C ON (Table_A.A_ID = B_AND_C.A_ID)
WHERE Table_A.ID = 3
You may not have to use an inline view. I'm not in front of a machine with MySQL right now so I can't check but you can try
SELECT *
FROM table_A a
LEFT JOIN (table_B b
INNER JOIN table_C c
ON b.c_id = c.c_id)
ON a.b_id = b.b_id
WHERE
a.a_id =3

how do i select the required attributes from a union of left join and right join

I have two tables on which I am unable to perform full outer join so I am doing a union of left and right outer join.
each table has attributes like
tableA - one,two,three,four
tableB - one,two,three,four
(SELECT * FROM tableA
LEFT OUTER JOIN tableB ON
tableA.two=tableB.two)
UNION
(SELECT * FROM tableA
RIGHT OUTER JOIN tableB ON
tableA.two=tableB.two)
You just need to alias the tables
SELECT a1.one, a1.two, b1.one, b1.two
FROM tableA a1
LEFT OUTER JOIN tableB b1
ON a1.two=b1.two
UNION
SELECT a2.one, a2.two, b2.one, b2.two
FROM tableA a2
RIGHT OUTER JOIN tableB b2
ON a2.two=b2.two;
As an aside, the "UNION ALL and exclusion JOIN" method described on this page is a more reliable way of implementing FULL OUTER JOIN in MySQL.

How sql server evaluates the multiple different joins?

i have a general question about how sql server evaluates the joins.The query is
SELECT *
FROM TableA
INNER JOIN TableB ON TableB.id = TableA.id
LEFT JOIN TABLEC ON TABLEC.id = TABLEB.id
Q1: What tables is the left join based on? I know it will based on the TABLEC but what is the other one? Is it the result of the first inner join or the TABLEB specified in the left join condition?
Q2: Is "LEFT JOIN TABLEC ON TABLEC.id = TABLEB.id" equivalent to "LEFT JOIN TABLEC ON TABLEB.id = TABLEC.id"
Q3: Is the query equivalent to the following one? (with TABLEB.id replaced by TABLEA.id?)
SELECT *
FROM TableA
INNER JOIN TableB ON TableB.id = TableA.id
LEFT JOIN TABLEC ON TABLEC.id = TABLEA.id
Thank you!
Q1: It is based on the result of the inner join, therefore it will only LEFT JOIN with items that are in TableA AND TableB.
Q2: Yes
Q3: Yes, it's a consequence of question Q1.
SQL is a declarative language. When you declare 'A JOIN B JOIN C' there is no order of join involved. The end result has to match the required criteria, but the underlying implementation is free to choose any actual implementation order.
At a logical level the inner JOIN operator is associative so the order does not matter: 'A JOIN B JOIN C' is identical with 'A JOIN C JOIN B' which is identical with 'B JOIN A JOIN C' and so on and so forth.