How sql server evaluates the multiple different joins? - sql-server-2008

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.

Related

mysql no response if left join 2 inner join table

I have tried to run a SQL statment that Left Join 2 inner join statement, but the MYSQL cannot load the result.
TableA about 100,000 records and TableB about 200,000 records.
The statement is similar at the below :
(The job is about accounting matters, a aging report, and determine which voucher is not paid)
SELECT a.*, b.* FROM
(SELECT tableA JOIN tableB ON tableA.id = tableB.id WHERE tableB.dramt != 0) a
LEFT JOIN
(SELECT tableA JOIN tableB ON tableA.id = tableB.id WHERE tableB.cramt != 0) b
ON a.invoiceno = b.invoiceno
I have tried to run the INNER JOIN statement separately, the result has returned in less than a second.
Is it about the server setting? Anyone has similar experience? Please kindly give me some advice with thanks.

MySQL with IF or EXISTS in WHERE

I have a problem with the following query for id’s not present in tableC. Despite the LEFT JOIN, an id in tableA and tableB is not in the results if the id is absent from tableC. And that is because the tableC.name doesn’t exist for these id’s. I imagined MySQL would then ignore the last part considering the clause to be true….but no.
SELECT
tableA.id, tableA.name
FROM
tableA
LEFT JOIN tableB ON tableA.id = tableB.id
LEFT JOIN tableC ON tableA.id = tableC.id
WHERE
tableA.latin = 'whatever'
AND RIGHT(tableC.name,2) != 'y'
I imagine there is a solution using either IF, CASE or EXISTS on the second part of the WHERE clause, but I don’t get the result I want with the following three attempts (I only show the last line):
WHERE
tableA.latin = 'whatever'
AND IF(tableC.name <> 0, RIGHT(tableC.name,2) != 'y', ' ');
This doesn’t give error either, but not the expected result:
WHERE
tableA.latin = 'whatever'
AND IF(tableC.name = true, RIGHT(tableC.name,2)!= 'y', ' ');
Trying the following with EXISTS gives me error in the MySQL Wordbench editor:
WHERE
tableA.latin = 'whatever'
AND if(EXISTS tableC.name, RIGHT(tableC.name,2) != 'y', ' ');
Any time you reference a column (tableC.name in your case) from a left-joined table in the where clause, you force the join to behave as if it were an inner join. Instead, move the test into the join condition.
SELECT tableA.id, tableA.name
FROM tableA
LEFT JOIN tableB
ON tableA.id = tableB.id
LEFT JOIN tableC
ON tableA.id = tableC.id
AND RIGHT(tableC.name,2) != 'y'
WHERE tableA.latin = 'whatever'
There is a much easier solution. Your where condition is turning the outer joins into inner joins. Just move the condition into the on clause:
SELECT tableA.id, tableA.name FROM tableA
LEFT JOIN tableB ON tableA.id = tableB.id
LEFT JOIN tableC ON tableA.id = tableC.id AND RIGHT(tableC.name, 2) <> 'y'
WHERE tableA.latin = 'whatever';
Of course, the expression RIGHT(tableC.name,2) != 'y' should always be true almost always, because you are looking for two characters and comparing to one. Perhaps you mean:
SELECT tableA.id, tableA.name FROM tableA
LEFT JOIN tableB ON tableA.id = tableB.id
LEFT JOIN tableC ON tableA.id = tableC.id AND tableC.name not like '%y'
WHERE tableA.latin = 'whatever';
How about this (untested but I think it should work):
SELECT tableA.id, tableA.name FROM tableA
LEFT JOIN tableB ON tableA.id = tableB.id
LEFT JOIN tableC ON (tableA.id = tableC.id AND RIGHT(tableC.name,2) != 'y')
WHERE tableA.latin = 'whatever'
It makes table c only include the ones you want but doesn't interfere with the left outer join.

Is left join commutative? What are its properties?

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.

mysql case statement for joining three table

there is three table
table a
table b
table c
and my query is :
select a.title,a.id,b.title
from table a
case when a.type=1 then
inner join table a.id=tableb.id end
case when a.type=2 then inner join table a.id=table c.id
But this query doesnt work.Can somebody helpe the right way to fetch or execute this type of query
You cannot use case in the from clause. To achieve this you could use UNION ALL. For instance:
select a.title,a.id,b.title
from table a inner join table b on a.id=b.id
where a.type=1
UNION ALL
select a.title,a.id,c.title
from table a inner join table c on a.id=c.id
where a.type=2
You cannot do something like "if this is 1 then join other table than if it is 2", you must join both and select accordingly:
SELECT
a.title,
a.id,
IF (tableb.title IS NOT NULL, tableb.title, tablec.title),
CASE a.type
WHEN 1 THEN tableb.id
WHEN 2 THEN tablec.id
END
FROM table a
LEFT JOIN tableb ON tablea.id = tableb.id
LEFT JOIN tablec ON tablea.id = tablec.id

Difference of "FROM a LEFT JOIN b" vs. "FROM a, b"

Do the queries do the same? What is the standard?
Will I lose performance if I change one of these ways of write the query?
Query 1
SELECT a.*, b.id AS b_id
FROM table_a AS a
LEFT JOIN table_b AS b
ON a.id = b.id
Query 2
SELECT a.*, b.id AS b_id
FROM table_a a, table_b b
WHERE a.id = b.id
They return different results.
A LEFT JOIN statement will return rows even if there is no associated records in table_b that match table_a id. So it will return all rows in table_a, paired with EITHER a matching row in table_a OR a blank/null table_b row (if for that row in table_a there isn't any matching row in table_b).
The second query is a shortcut for an INNER JOIN. This query will ONLY exclusively return rows that match the condition a.id = b.id. The second query can also be written as:
SELECT a.*, b.id AS b_id
FROM table_a a
INNER JOIN table_b b
ON a.id = b.id
To answer your performance question, please see the answers on a related SO thread here.