Where to put conditions in Multiple Joins? - mysql

Say if I have this query
SELECT TableA.Id, TableA.Number, TableA.Name, TableA.HOl, TableB.Contact, TableC.activity
FROM TableA
left JOIN TableB on TableA.Id = TableB.TableA_Id
left join TableC on TableB.userid = TableC.userid
where TableA.hol = 50
order By TableA.Id
Is it better to but the TableA.Hol in the where or in the ON clause?
I am not sure if it makes a difference, I am trying to determine why it slow. Maybe it something else with my joins?

This is your query:
select TableA.Id, TableA.Number, TableA.Name, TableA.HOl, TableB.Contact, TableC.activity
from TableA left join
TableB
on TableA.Id = TableB.TableA_Id left join
TableC
on TableB.userid = TableC.userid
where TableA.hol = 50
order By TableA.Id;
A left join keeps all rows in the first table, regardless of what the on clause evaluates to. This means that a condition on the first table is effectively ignored in the on clause. Well, not exactly ignored -- the condition is false so the columns from the second table will be NULL for those rows.
So, filters on the first table in a left join should be in the where clause.
Conditions on subsequent tables should be in the on clause. Otherwise, those conditions will turn the outer join into an inner join.

SELECT A.Id, A.Number, A.Name, A.HOl, B.Contact, C.activity
FROM TableA A
LEFT OUTER JOIN TableB B
ON (A.Id = B.TableA_Id)
LEFT OUTER JOIN TableC C
ON (B.userid = C.userid)
AND A.hol = 50
ORDER BY A.Id
If you are referencing more than one table you can use an alias which improves readability. But this has nothing to do with performance.

Regardless of whether you are using JOIN or LEFT JOIN, use ON to specify how the tables are related and use WHERE to filter.
In the case of JOIN, the it does not matter where you put the filtering; it is for readability that you should follow the above rule.
In the case of LEFT JOIN, the results are likely to be different.
If you do
EXPLAIN EXTENDED SELECT ...
SHOW WARNINGS;
you can see what the SQL parser decided to do. In general, it moves ON clauses are to WHERE, indicating that it does not matter (to the semantics) which place they are. But, for LEFT JOIN, some things must remain in the ON.
Note another thing:
FROM a ...
LEFT JOIN b ...
WHERE b.foo = 123
effectively throws out the LEFT. The difference between LEFT and non-LEFT is whether you get rows of b filled with NULLs. But WHERE b.foo = 123 says you definitely do not want such rows. So, for clarity for the reader, do not say LEFT.
So, I agree with your original formulation. But I also like short aliases for all tables. Be sure to qualify all columns -- the reader may not know which table a column is in.
Your title says "multiple" joins. I discussed a single JOIN; the lecture applies to any number of JOINs.

Related

SQL inner join multiple tables with one query

I've a query like below,
SELECT
c.testID,
FROM a
INNER JOIN b ON a.id=b.ID
INNER JOIN c ON b.r_ID=c.id
WHERE c.test IS NOT NULL;
Can this query be optimized further?, I want inner join between three tables to happen only if it meets the where clause.
Where clause works as filter on the data what appears after all JOINs,
whereas if you use same restriction to JOIN clause itself then it will be optimized in sense of avoiding filter after join. That is, join on filtered data instead.
SELECT c.testID,
FROM a
INNER JOIN b ON a.id = b.ID
INNER JOIN c ON b.r_ID = c.id AND c.test IS NOT NULL;
Moreover, you must create an index for the column test in table c to speed up the query.
Also, learn EXPLAIN command to the queries for best results.
Try the following:
SELECT
c.testID
FROM c
INNER JOIN b ON c.test IS NOT NULL AND b.r_ID=c.testID
INNER JOIN a ON a.id=b.r_ID;
I changed the order of the joins and conditions so that the first statement to be evaluated is c.test IS NOT NULL
Disclaimer: You should use the explain command in order to see the execution.
I'm pretty sure that even the minor change I just did might have no difference due to the MySql optimizer that work on all queries.
See the MySQL Documentation: Optimizing Queries with EXPLAIN
Three queries Compared
Have a look at the following fiddle:
https://www.db-fiddle.com/f/fXsT8oMzJ1H31FwMHrxR3u/0
I ran three different queries and in the end, MySQL optimized and ran them the same way.
Three Queries:
EXPLAIN SELECT
c.testID
FROM c
INNER JOIN b ON c.test IS NOT NULL AND b.r_ID=c.testID
INNER JOIN a ON a.id=b.r_ID;
EXPLAIN SELECT c.testID
FROM a
INNER JOIN b ON a.id = b.r_id
INNER JOIN c ON b.r_ID = c.testID AND c.test IS NOT NULL;
EXPLAIN SELECT
c.testID
FROM a
INNER JOIN b ON a.id=b.r_ID
INNER JOIN c ON b.r_ID=c.testID
WHERE c.test IS NOT NULL;
All tables should have a PRIMARY KEY. Assuming that id is the PRIMARY KEY for the tables that it is in, then you need these secondary keys for maximal performance:
c: INDEX(test, test_id, id) -- `test` must be first
b: INDEX(r_ID)
Both of those are useful and "covering".
Another thing to note: b and a is virtually unused in the query, so you may as well write the query this way:
SELECT c.testID,
FROM c
WHERE c.test IS NOT NULL;
At that point, all you need is INDEX(test, testID).
I suspect you "simplified" your query by leaving out some uses of a and b. Well, I simplified it from there, just as the Optimizer should have done. (However, elimination of tables is an optimization that it does not do; it figures that is something the user would have done.)
On the other hand, b and a are not totally useless. The JOIN verify that there are corresponding rows, possibly many such rows, in those tables. Again, I think you had some other purpose.

select records from 3 tables with same column id

I am trying to write an SQL query which will select records of a student within 3 tables that have the same column_I'd.
This is what I wrote but the the records selected are not accurate:
select
Nov_DEC_billing.*,
Nov_DEC_students_portfolio.*,
admission_form.academic_year
from
Nov_DEC_billing,
Nov_DEC_student_portfolio,
admission_form
where
Nov_DEC_billing.ID = Nov_DEC_student_portfolio.ID=admission_form.ID
AND
admission_form.Program ='Nov/dec'
I get a records selected alright but its not accurate. Please what's the right way to join 3 tables that share the same column_id.???
Use JOIN in your query
SELECT b.*, p.*, a.academic_year
FROM Nov_DEC_billing b
JOIN Nov_DEC_student_portfolio p ON p.id = b.id
JOIN admission_form a ON a.id = b.id
WHERE a.Program='Nov/dec'
You need to join tables something like this:
SELECT Nov_DEC_billing.*,
Nov_DEC_students_portfolio.*,
admission_form.academic_year
FROM Nov_DEC_billing AS ndb,
LEFT JOIN Nov_DEC_student_portfolio AS ndsp ON ndsp.ID=ndb.ID,
LEFT JOIN admission_form AS af ON af.ID=ndb.ID
WHERE af.Program='Nov/dec'
You should join all the tables to a single one.
What you will is join all the tables to a single one and then select from it.
Since you have 2 tables you should first join 2 and then join another one on the result.
See here left join example for the exact syntax.
Nov_DEC_billing.ID=Nov_DEC_student_portfolio.ID=admission_form.ID
doesn't do what you expect. It takes the first part, Nov_DEC_billing.ID=Nov_DEC_student_portfolio.ID and evaluates it. If the values match, that part becomes a 1, if they don't match, it becomes 0. Then the 0 or the 1 is compared against admission_form.ID. That is very likely to give strange results.
So you'd have to split that into:
Nov_DEC_billing.ID=Nov_DEC_student_portfolio.ID
AND Nov_DEC_student_portfolio.ID=admission_form.ID
Or just use explicit join syntax, as the others already advised (and which I do too). That forces you to split this anyway.

left/right join performance

Is there a different between in left and right join, the below sql statements are same result, but is the both is the same performance?
SELECT count(*)
FROM writers
RIGHT JOIN blogs ON blogs.members_id = model_id
WHERE member_id = 123 AND blogs.status = 1;
SELECT count(*)
FROM blogs
LEFT JOIN writers ON writers.model_id = blogs.members_id
WHERE writers.member_id = 123
AND blogs.status = 1;
No difference at all. Both are implementing inner joins. Huh? You think you specified an outer join, but your where clause is undoing it.
Presumably, you intend:
SELECT count(*)
FROM blogs b LEFT JOIN
writers w
ON w.model_id = b.members_id AND w.member_id = 123
WHERE b.status = 1;
Although you can write this as a RIGHT JOIN, I strongly discourage it. Here are some reasons:
SQL is read left-to-right. It is easier to follow "keep all the rows in the first table" than "keep all the rows in the last table which I haven't yet read".
SQL is parsed left-to-right. For a single join, this doesn't make a difference. But with multiple joins, there are subtle differences between A LEFT JOIN B LEFT JOIN C and C RIGHT JOIN B RIGHT JOIN A.

MySQL JOINS without where clause

I know that in MySQL SQL it only makes sense to index those fields you use in the WHERE clause. But if you are using JOINS, i believe that the JOIN also acts as the WHERE clause because it is comparing two fields. For example:
select b.name, p.location
from Branch as p, Person as p
where b.id = p.id;
is the same as
select b.name, p.location
from Branch as p
INNER JOIN Person as p ON (p.id = b.id);
So my understanding is that the INNER JOIN = WHERE clause in a way, or translated that way by MySQL, and hence can be indexed on i.e, a columns used on a JOIN are indexed (if they have indexes created on them). Is my understanding correct?
Where and Join are pretty similar. However, Join is more at table level, and where is more at column level. Yes, you are corrrect.

Search data from two table with joins how to handler null values

I have write a search query that will joining two different table. i have putted left join on both. Now first table contains 60records while based on that second table has only 30. Now i wanted if i search query should return all 60records. right now it is returning 30.
query same.
select A.,B. from A left join B on A.Id=B.AId where
A.name=IfNull('tst',A.name) AND B.class=IFNull('c',B.class).
Please guide me, Thanks.
It's wise to remember that JOIN operations (all kinds of JOIN operations, LEFT, RIGHT, INNER, OUTER) have the purpose of creating a new, virtual, table that is assembled from the tables joined together.
What is this JOINed virtual table supposed to have in it? In your case, what is the meaning of your column A.ID, and your column B.AID?
Are there rows in your A table with A.ID column values which occur no times in B.AID?
Are there rows in your B table with B.AID column values which occur no times in A.ID?
If the answer to question 1 is Yes and question 2 is No, then a LEFT JOIN will give you want you want. But simplify your query. Try this.
SELECT A.*, B.*
FROM A
LEFT JOIN B ON A.ID = B.AID
If you happen to want only the rows from A where there is no corresponding row from B, try this.
SELECT A.*
FROM A
LEFT JOIN B ON A.ID = B.AID
WHERE B.AID IS NULL
If the answer to both questions is Yes, then you may want this:
SELECT A.*, B.*
FROM A
OUTER JOIN B ON A.ID = B.AID
But you should think this through very carefully.
Try this Logic i hope it will work for you.....
select A.*,B.* from A left join B on A.Id=B.AId where B.Id != ''