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

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.

Related

Join two tables without mixing rows

I want to join 2 tables and for each joined result I need a separate row, but the rows of my query result are somehow mixed:
Schema + Data:
My Query:
SELECT Table_A.id,
Table_B.id,
Table_C.id
FROM Table_A
LEFT JOIN Table_B
ON Table_B.id_a = Table_A.id
LEFT JOIN Table_C
ON Table_C.id_a = Table_A.id
The Result:
What I want (3 separate rows - separated by the join-tables' id-column):
Q: What am I doing wrong?
=> You could put it in that way: I need all rows of where id_a is 1 + table_a.id=1. Maybe JOIN is the wrong approach here..?
You need INNER JOIN UNION :
SELECT A.id A_Id, B.id B_Id, ''c_id
FROM Table_A A
INNER JOIN Table_B B ON B.id_a = A.id
UNION ALL
SELECT A.id A_Id, '' B_Id, c.id c_id
FROM Table_A A
INNER JOIN Table_C C ON A.id = C.id_a

MySql strange performance

First of all, for example I have 3 table A, B, C. Table A has relation with table B and table has relation with table C. I want to get SUM of some field from table A which depends on some fields from table C.
Table A has > 300k rows, Table B has > 4k rows, Table C has ~ 100 rows
My query looks like that:
SELECT SUM(a.hours) AS total
FROM table_a a
LEFT JOIN table_b b
ON a.table_b_id = b.id
LEFT JOIN table_c c
ON b.table_c_id = c.id
WHERE a.customer_id = 1
AND c.title IN ('Title D','Title E')
Query execution time is ~7 sec, it's very slow. But execution time of query like below is ~0.0 sec.
SELECT a.hours
FROM table_a a
LEFT JOIN table_b b
ON a.table_b_id = b.id
LEFT JOIN table_c c
ON b.table_c_id = c.id
WHERE a.customer_id = 1
AND c.title IN ('Title D','Title E')
Why SUM is so slow? what should I do?
Move your condition to ON clause for related table:
SELECT SUM(a.hours) AS total
FROM table_a a
LEFT JOIN table_b b
ON a.table_b_id = b.id
LEFT JOIN table_c c
ON b.table_c_id = c.id
AND c.title IN ('Title D','Title E')
WHERE a.customer_id = 1
EDIT 1 According to #dnoeth comment I can agree, probably we should use inner join when join table_c:
SELECT SUM(a.hours) AS total
FROM table_a a
LEFT JOIN table_b b
ON a.table_b_id = b.id
INNER JOIN table_c c
ON b.table_c_id = c.id
AND c.title IN ('Title D','Title E')
WHERE a.customer_id = 1
Use LEFT JOIN in both places and add this composite index:
INDEX(customer_id, title)

MySQL: How to skip where statement when the matched data does not exist

For example, I execute this MySQL statement
SELECT table1.a, table2.b, table3.c FROM table1, table2, table3
WHERE
a.id = b.id
AND
a.id = c.id
When there are some rows where a.id = b.id but no rows where a.id = c.id in this case,
no rows are shown in the result.
So, I want to make SQL to ignore a.id = c.id statement and show only rows that a.id = b.id is true.
Could you tell me how to do this? Thank you.
You should always use explicit join syntax. A simple rule: never use commas in the from clause.
Your query, properly written, is:
SELECT table1.a, table2.b, table3.c
FROM table1 a join
table2 b
on a.id = b.id join
table3 c
on a.id = c.id;
I notice the table aliases you use (a', b, and c) are the same as the column names. This is unusual, but allowed.
If you want to keep the records from a, then switch to left join:
SELECT table1.a, table2.b, table3.c
FROM table1 a left join
table2 b
on a.id = b.id left join
table3 c
on a.id = c.id;
This syntax is superior to the implicit join because it supports outer joins. Most people also think it is also more readable and clearer.

SQL LEFT JOIN only newest right column entry?

So I have two tables like this:
create table A
{
id int;
...
}
create table B
{
id int;
a_id int;
t timestamp;
...
}
A is one-to-many with B
I want to:
SELECT * FROM A LEFT JOIN B ON A.id = B.a_id ???
But I want to return exactly one row for each entry in A which has the B with the newest t field (or null for Bs fields if it has no B entry).
That is rather than returning all A-B pairs, I want to only select the newest one with respect to A (or A-null if no B entry).
Is there some way to express this in SQL? (I'm using MySQL 5.5)
LEFT JOIN is only concerned with ensuring every row in A is returned, even if there is no corresponding joined row in B.
The need for just one row needs another condition. MySQL is limitted in its options, but one could be:
SELECT
*
FROM
A
LEFT JOIN
B
ON B.id = A.id
AND B.t = (SELECT MAX(lookup.t) FROM B AS lookup WHERE lookup.id = A.id)
Another could be...
SELECT
*
FROM
A
LEFT JOIN
(
SELECT id, MAX(t) AS t FROM B GROUP BY id
)
AS lookup
ON lookup.id = A.id
LEFT JOIN
B
ON B.id = lookup.id
AND B.t = lookup.t
You could do the following:
SELECT A.*, B.*
FROM
A
LEFT JOIN
(SELECT B.a_id, MAX(t) as t FROM B GROUP BY B.a_id) BMax
ON A.id = BMax.a_id
JOIN B
ON B.a_id = BMax.a_id AND B.t = BMax.t
you first need to get the newest t from tableB in a subquery, then join it with tableA and tableB.
SELECT a.*, c.*
FROM tableA a
LEFT JOIN
(
SELECT a_ID, max(t) maxT
FROM tableB
GROUP BY a_ID
) b on a.a_id = b.a_ID
LEFT JOIN tableB c
ON b.a_ID = c.a_ID AND
b.maxT = c.t
try this:
SELECT *
FROM tableA A LEFT JOIN
(select a_id ,max(t) as max_t
from tableB
group by a_id )b
on A.id = b.a_id
and A.t=b.max_t

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