I'm trying to join 4 tables, two 1-N ones and one through an N-N table. Strangely mySql doesn't seem to like one of my syntaxes. Does anybody know if this is due to myOwn limitations or mySql?
This doesn't work:
SELECT *
FROM tableOne t1 JOIN tableTwo t2
LEFT OUTER JOIN N_N_tableThree t3
JOIN tableFour t4 ON t4.id = t3.fk_tableFour
ON t2.id = t3.fk_tableTwo
ON t2.id = t1.fk_tableTwo
While this does work
SELECT *
FROM tableOne t1,
tableTwo t2 LEFT OUTER JOIN N_N_tableThree t3
JOIN tableFour t4 ON t4.id = t3.tableFour_id
ON t2.id = t3.tableTwo_id
WHERE t2.id = t1.tableTwo_id
Anybody a clue?
Thanks for answering.
Use this syntax instead:
SELECT *
FROM tableOne t1
INNER JOIN tableTwo t2 ON t2.id = t1.fk_tableTwo
LEFT JOIN N_N_tableThree t3 ON t2.id = t3.fk_tableTwo
INNER JOIN tableFour t4 ON t4.id = t3.fk_tableFour;
This will be equivalent of the second query that worked.
Because the WHERE t2.id = t1.tableTwo_id in the second query is actually an INNER JOIN1, which will be the same as INNER JOIN tableTwo t2 ON t2.id = t1.fk_tableTwo as I did. This is the old JOIN syntax, try to avoid it and use the ANSI SQL-92 syntax instead as I did. For more information see this:
Bad habits to kick : using old-style JOINs.
The query you posted didn't work, because it is not the correct syntax for JOIN in MySQL, you have three ON clauses after each others:
...
ON t4.id = t3.fk_tableFour
ON t2.id = t3.fk_tableTwo
ON t2.id = t1.fk_tableTwo
Each JOIN should has the join condition specified with the ON clause after the JOIN directly, if not it would a cross join2. But not multiple ON's the way you did.
SQL Fiddle Demo
1: Don't be confused with the use of INNER JOIN instead of JOIN they are the same the default JOIN is inner join, I just I used for readability. Also, the same thing with the OUTER keyword, I omit it in LEFT JOIN since it is optional when using LEFT or RIGHT
2: You will find other variations of the JOIN syntax in MySQL in the reference page, like the JOIN tablename without a join condition, and others. You might need to read them.
Related
Assuming t is a large table, and the following two queries
SELECT t1.value, t2.value
FROM t as t1 JOIN t as t2
ON t1.id = t2.id
WHERE t1.key = '123'
and
SELECT t1.value, t2.value
FROM t as t1 JOIN t as t2 JOIN t as t3
ON t1.id = t2.id
WHERE t1.key = '123'
the second one having a JOIN with a table that is not used in the SELECT.
The second query executes much slower. I expected that MySQL would figure out that the third JOIN is not used and will just ignore it. But it does not?
Your second query doesn't have an ON clause for the second join:
SELECT t1.value, t2.value
FROM t as t1
JOIN t as t2
JOIN t as t3 ON t1.id = t2.id
WHERE t1.key = '123';
This means that every matching record in t1 will be joined onto every record in t2. This is, perhaps, what you meant:
SELECT t1.value, t2.value
FROM t as t1
JOIN t as t2 ON t1.id = t2.id
JOIN t as t3 ON t1.id = t3.id
WHERE t1.key = '123';
This will perform much more reasonably because it isn't creating a huge number of results.
If you intended to do a full join onto t3:
SELECT t1.value, t2.value
FROM t as t1
JOIN t as t2 ON t1.id = t2.id
JOIN t as t3
WHERE t1.key = '123';
Then this will be slower because, even though you are not SELECTing a field from t3 it does change the output because it produces extra rows.
See here for examples http://sqlfiddle.com/#!9/e86c9/3
This is because the default JOIN in mySQL implies INNER JOIN.
The third join will not be ignored because this will alter the eventual data set you get back after executing the query.
This stackoverflow question contains more detailed information
It is not that the MySQL optimizer isn't smart enough to remove the unused query, it is just that you are using the wrong syntax here. As the documentation states, your query will be performed as:
JOIN t as t2 JOIN t as t3 --> t2 CROSS JOIN t3
The syntax you are using isn't standard SQL and cannot be used in any SQL standard compliant database. Take a look at the specific MySQL JOIN documentation here .
Suppose I have following tables: T1,T2 and T3.
How could I rephrase the following query using only left joins.
Select *
From T1
Right join T2 On T1.FK2=T2.PK
Right join T3 On T1.FK3=T3.PK
Following attempt is not correct:
Select *
From T2
Left join T1 On T1.FK2=T2.PK
Left join T3 On T1.FK3=T3.PK
T3 is On the wrong Side of the join. Is the following possible:
Select *
From T2
Left join T3 On T1.FK3=T3.PK
Left join T1 On T1.FK2=T2.PK
I can't Find a way to put both tables 2 and 3 On the left Side of 1 and use the correspondent fields to join all tables? The last query uses fields of table 1 before this table is mentioned in the query.
Or something like this?
Select *
From T2
Left join (
T3 left join T1
On T1.FK3=T3.PK)
On T1.FK2=T2.PK
Apparently brackets can help to order your joins. I wonder if this is really documented, i've found Nothing at first glance in the mysql docs.
Following query is correct and does not have any subqueries:
Select T1.Id Ida, t2.id idb, T3.id idc FROM T3
LEFT JOIN
(T2
LEFT JOIN T1 ON (T1.ID = T2.ID))
ON (T1.ID= T3.ID);
You need to use a subquery to first join t1 with t2 and then join the result with t3:
SELECT T.ID1 ID1, T.ID2 ID2, T3.ID ID3 FROM T3
LEFT JOIN
(SELECT T1.ID ID1, T2.ID ID2 FROM T2
LEFT JOIN T1 ON (T1.ID = T2.ID)) T
ON (T.ID1 = T3.ID);
SQL Fiddle
The first way is just to reverse the order that the tables are mentioned:
Select *
from t3 left outer join
t2
on T1.FK3 = T3.PK left outer join
t1
on T1.FK2 = T2.PK
But this won't work, because the first condition is on t1 and not t2. And t2 hasn't yet been defined.
When working with chains of tables in left or right outer joins, only the first (or last) tables are important, because they "drive" the query. "Drive" in the sense that they provide all the values even when there are no matches. So, the following should do what you want:
Select *
from t3 left outer join
t1
on T1.FK3 = T3.PK left outer join
t2
on T1.FK2 = T2.PK;
I have 4 tables, one of which I need to update.
Table t1 needs to be updated according to the information in table t2 (t1.id = t2.id)
Table t2 contains information about websites (e.g.ID, traffic ).
Table t3 is a m:n table, that links the IDs in table t2 with the languages in table t4 based on language codes (ISO2) (e.g. XID: 1 | ISO2: EN,DE,FR)
Table t4 contains the ISO2-Codes (e.g. EN, DE, FR) and the respective languages (English, German, French)
Now I need to update the languages column in table t1 based on the information in tables t2,t3,t4.
I have written the following query, but it says SQL Error (1111): Invalid use of group function */
UPDATE t1
LEFT JOIN t2
ON t1.id = t2.id
LEFT JOIN t3
ON t2.id = t3.X_id
LEFT JOIN t4
ON t3.languages_iso2 = t4.iso2
SET t1.languages = GROUP_CONCAT(t4.`language` ORDER BY t4.language ASC)
I know that this solution can't be the most elegant one, but my SQL skills are not that good, so I don't know what else I should try. Does anyone have a solution for this problem?
Thanks in advance!
Try this:
UPDATE t1
INNER JOIN (SELECT t2.id, GROUP_CONCAT(t4.language ORDER BY t4.language) languages
FROM t2
INNER JOIN t3 ON t2.id = t3.X_id
INNER JOIN t4 ON t3.languages_iso2 = t4.iso2
GROUP BY t2.id
) AS t2 ON t1.id = t2.id
SET t1.languages = t2.languages;
If I have
SELECT * FROM Table1 t1
LEFT JOIN Table2 t2 ON t1.id = t2.id
WHERE t1.user='bob';
Does the WHERE clause run after the two tables are JOINED?
How do I make it so it runs prior to the JOIN?
The where clause will be executed before the join so that it doesn't join unnecessary records. So your code is fine the way it is.
Change the WHERE to another JOIN condition
LEFT JOIN Table2 t2 on t1.id = t2.id AND t1.user='bob'
In my experience in a left join you cannot exclude records in the 'left' (t1) table in the ON-statement since - by definition - all t1 records will be included. The where statement does work as it will be applied to the result of the join afterwards.
I do not exactly know what you want to achieve but most probably an inner join suits your needs as well and then you can add the t1.user='bob' condition to the ON-statement.
But if Mosty Mostacho is correct, the location (WHERE vs ON) of the condition is not relevant for speed of execution.
You should just add t1.user='bob' condition to ON clause before other condition and it will be evaluated first:
SELECT * FROM Table1 t1
LEFT JOIN Table2 t2
ON t1.user='bob' AND t1.id = t2.id;
What you may use is table expression after FROM like this:
SELECT *
FROM (SELECT
id
FROM Table1
WHERE user = 'bob') AS t1
LEFT JOIN Table2 t2
ON t1.id = t2.id
you can do
SELECT *
FROM Table1 t1
LEFT JOIN Table2 t2
ON t1.id=t2.id AND t1.user='bob';
RIGHT JOIN was the solution:
SELECT cars.manufacturer, cars.year FROM cars
RIGHT JOIN (SELECT m.manufacturer FROM cars AS m ORDER BY m.year DESC LIMIT 3) subq
ON cars.manufacturer=subq.manufacturer
Haven't put it through the full rigors yet, but seems to work.
I have two tables:
T1
1,a
2,b
T2
2,ggg
3,hhh
I want the join between them to give me all fields:
1,a,null,null
2,b,2,ggg
null,null,3,hhh
MySQL doesn't have FULL OUTER JOIN, but you can emulate it e.g.:
SELECT * FROM T1 LEFT OUTER JOIN T2 ON T1.id = T2.id
UNION ALL
SELECT * FROM T1 RIGHT OUTER JOIN T2 ON T1.id = T2.id
WHERE T1.id IS NULL;
In general:
FULL OUTER JOIN = LEFT OUTER JOIN ∪ (RIGHT OUTER JOIN ∖ INNER JOIN)
You need to cut one inner join (in here from right join, but IMHO doesn't matter which one you choose), because both returns same inner joins. In here you have:
T1::
T2::
LEFT OUTER JOIN::
RIGHT OUTER JOIN::
INNER JOIN::
FULL OUTER JOIN::
If the tables have a (combination of) columns that is unique, you can build a list of ids in a subquery. Then you can use two outer joins to simulate a full outer join:
select *
from (
select col1
from t1
union
select col1
from t2
) ids
left join
t1
on ids.col1 = t1.col1
left join
t2
on ids.col1 = t2.col1