Order of keys in the LEFT JOIN condition - mysql

What happens when we reverse the order of keys in the LEFT JOIN condition?
Ideal SQL left join syntax for joining two tables is
select fields
from tableA
LEFT JOIN tableB
ON tableA.key = tableB.key
Flipped order of join condition
select fields
from tableA
LEFT JOIN tableB
ON tableB.key = tableA.key -- (order flipped)
Will these queries produce different set of results?

You will get the same results. The on clause just evaluates to true or false; the order does not matter.
Only the position of the tables themselves matter. e.g. reversing table order as below would give different results.
select fields
from tableB
LEFT JOIN tableA
ON tableA.key = tableB.key

LEFT JOIN is not commutative, you can't switch arguments: tableA LEFT JOIN tableB is equivalent to tableB RIGHT JOIN tableA, and different from tableB LEFT JOIN tableA.
== is commutative, you can switch arguments: tableA.key = tableB.key is equivalent to tableB.key = tableA.key.

No any difference, except readability of the query.
SQL was designed to be readable as usual English text. In a usual text, when we want to specify any mentioned object, we say something like "An object. This object is like that object, this object is related to that object, and this object has those properties." We do not say "That object is like this object, to that object related this object and those properties have this object".
So, when we adding records of TableB to query from TableA, we need to specify what must have a record from TableB to satisfy current record from TableA. So we must say, wee need that records from TableB, which have an id, equal to TableA.ID. TableB.id = TableA.id. We must write exactly in this order, to provide easy reading and understanding of this relation.

Related

MySQL: Trouble trying to get my SQL statement to work when condition is true but can also accept false

I have the following statement:
SELECT tableA.*, tableB.* FROM tableA, tableB WHERE tableA.userUUID = ? AND tableB.uuid=tableA.tableBUUID
So when a record in table A has a valid tableBUUID and the tableBUUID exists in tableB then the query runs file. But when I removed the tableBUUID from table B without removing it from the record in tableA then the query returns nothing (Which is obviously expected)
I am wondering how I can change the query so that even if the tableBUUID does not match anything, the query will still return what it can even if its nothing/ blank columns from tableB?
Thanks all
You can achieve this via a LEFT JOIN:
SELECT tableA.*, tableB.*
FROM tableA
LEFT JOIN tableB ON tableB.uuid = tableA.tableBUUID
WHERE tableA.userUUID = ?
Fiddle.
Performing a LEFT JOIN will return data from tableA and matching records from tableB if it exists in tableB, otherwise it'll return only the records from tableA.
In the syntax you posted above in your question, you're essentially doing a INNER JOIN by comma separating your tables. This is the old syntax, moving forward you should explicitly write INNER JOIN like so:
SELECT * FROM tableA a INNER JOIN tableB b ON a.column_key = b.column_key
Read more about it in the following previous question:
What's the difference between comma separated joins and join on syntax in MySQL?

MYSQL - using AND in JOIN versus WHERE clause

If I have this query:
select * from tableA
left outer join tableB on tableA.id=tableB.id
AND tableB.foo = 1
where tableA.owner=10
I get 29 results, but if I move that AND into the WHERE clause like:
select * from tableA
left outer join tableB on tableA.id=tableB.id
where tableA.owner=10
AND tableB.foo = 1
I then get only 17 results.
I've looked all around and cannot find a definitive guide as to how using the AND differs when you use it in the JOIN versus the WHERE clause. Can anyone explain this to me?
Also, if I do something like AND tableB.foo = NULL in the JOIN all of my tableB.foo fields are NULL in the query results, even if they are not null in the table. Does having the AND in the JOIN clause change that field in the FROM selection before being filtered by the WHERE clause?
All of the criteria for the table you are outer-joining to should be in the JOIN clause (like your first query). Putting it in the WHERE clause (like your second query) implicitly converts the OUTER JOIN to an INNER JOIN.
As for your question about AND tableB.foo = NULL that is not proper MySQL syntax. NULLs require special treatment, using operators like IS NULL. You should use AND tableB.foo IS NULL instead.
An outer join joins just the same as an inner join. With the addition that when there is no match for a record, a dummy record with all columns set to null gets joined (so you still get the row from the first table in your results).
In your first query you are looking for matches in tableB with the same ID and foo = 1. For records in tableA with no such match you still get a result row (with all tableA fields null).
In the second query you are looking for matches in tableB with the same ID. For records in tableA with no such match you still get a result row (with all tableA fields null). Then in your where clause you only keep rows with foo = 1. This dismisses all outer-joined records (because their foo is null) and you are where you would have been with a plain inner join.
So always put all criteria on an outer-joined table in the ON clause. (There is one exception though; an anti join, but you can learn that pattern another time.)

How this queries will be evaluated? and, join syntax

How this queries will be evaluated?
(what i ask is: what will be the logic that the db-engine will use to gather the data?)?
A:
SELECT tableA.* FROM tableA
LEFT JOIN tableB ON tableB.key1 = tableA.key1
INNER JOIN tableC ON tableC.key2 = tableB.key2
B:
SELECT tableA.* FROM tableA
INNER JOIN tableC
LEFT JOIN tableB
ON (tableB.key1 = tableA.key1) AND (tableC.key2 = tableB.key2)
C:
What is the syntax, for joining multiple tables? (A and B for example)
D:
What is the logic behind the order of joins?
(How different joins (left, and inner) should be combines in a query?)
ANY-one?
SELECT tableA.* FROM tableA
LEFT JOIN tableB ON tableB.key1 = tableA.key1
INNER JOIN tableC ON tableC.key2 = tableB.key2
Since no brackets are used this should be evaluated left-to-right, so:
SELECT tableA.*
FROM
(tableA LEFT JOIN tableB ON tableB.key1 = tableA.key1)
INNER JOIN tableC ON tableC.key2 = tableB.key2
Meaning you first select all records from table A, with the matching records from B if they exist (outer join). That result set is then joined with C, but since you join on B.Key, all previous records where B = null will now disappear.
I am quite sure that the first join could be an inner join, giving the same result.
SELECT tableA.* FROM tableA
INNER JOIN tableC
LEFT JOIN tableB
ON (tableB.key1 = tableA.key1) AND (tableC.key2 = tableB.key2)
Now we first cross-join every record from A with every record from C (cartesian product).
That (possibly huge and possibly meaningless) resultset we extend with data from B where we can find it (meaning we add a record from B wherever we have a match with either A or B).
In general, when joining several tables, just take it step by step and always try to realize what you are joining with what. When in doubt, use brackets :)

MySQL left join, less results

I've got a little problem, I'm stuck with. I got two tables. The first one holds all id's, the second one some, but not all from tableA, a value and a corresponding identifier. As I thought I had it understood, a left join on the id's should give me all id's in the first table and null for the second, if the id doesn't exist in tableB. But I keep getting the number of id's that exist in both tables. Did I get the concept wrong?
My statement so far is:
SELECT tableA.id, tableB.desiredValue
FROM tableA
LEFT JOIN tableB ON tableA.id=tableB.item_id
WHERE tableB.element_id = 'something'
OR tableB.element_id IS NULL;
Any pointers?
Thanx, best regards,
Marcus
Move the condition that involves tableB column from WHERE to ON:
SELECT tableA.id, tableB.desiredValue
FROM tableA
LEFT JOIN tableB ON tableA.id=tableB.item_id
AND tableB.element_id = 'something'
--- WHERE tableB.element_id IS NULL --- this is probably not appropriate
;
Try this
SELECT tableA.id, tableB.desiredValue
FROM tableA
LEFT JOIN tableB ON tableA.id=tableB.item_id
AND (tableB.element_id = 'something'
OR tableB.element_id IS NULL);
In general, this seems like it should work. I'd be more specific in the where clause, however:
SELECT tableA.id, tableB.desiredValue
FROM tableA
LEFT JOIN tableB ON tableA.id = tableB.item_id
WHERE tableB.element_id = 'something' OR tableB.item_id IS NULL;
I've substituted item_id as the row I'm checking for NULL in -- though it should make a difference unless element_id can be NULL in rows where the join works.
Can you expand on why you want the other portion of the where clause -- tableB.element_id = 'something' ? My general recommendation if you just want all rows returned would be to eliminate the WHERE clause entirely.
Can you explain a bit more what the criteria are for the rows you want returned in general?

Any value to "TableB" in "LEFT JOIN TableB ON TableA.name = TableB.name"?

All,
I'm reviewing some basic MySQL JOIN tutorials. Jeff Atwood gives an example on his blog that goes like this:
SELECT * FROM TableA
LEFT OUTER JOIN TableB
ON TableA.name = TableB.name
It seems to me that the query doesn't need - from a semantic standpoint - the TableB mention on the second line. Do I understand that correctly? It seems to me that all the info is already available in the 3rd line.
I'm not trying to stir any type of trouble about the efficiency of the SQL language, I just want to understand whether this mention of TableB brings any new info, in this context or in others.
It doesn't bring new info, but it does bring precision and the ability for you to alias the table:
SELECT a.* FROM TableA a
LEFT OUTER JOIN TableBWhichHasAReallyLongUnweildyName b
ON a.name = b.name
Note that in this formulation I can both explicitly ask for the data from a and figure out the join more easily in line 3. However, the compiler wouldn't have non-arbitrary guidance as to where to get that information of what table to use unless I explicitly declare it. Consider if this was the way SQL worked:
SELECT b.* FROM TableA a
LEFT OUTER JOIN
ON TableA.name = TableB.name b
WHERE TableB.value v > 1
Am I saying that the tableB is aliased 'b', or TableB.name is aliased 'b'? It's just confusing; better to be explicit and authoritative.
TableB is only present on the third line because the columns you're joining on aren't uniquely named.
For example, say you wanted to join TableA and TableB on columns Foo and Bar, where only TableA has a ciolumn called Foo and only TableB has a column named Bar. Then you could write this:
SELECT * FROM TableA
LEFT OUTER JOIN TableB
ON Foo = Bar