I can do it in sybase and I can do it in oracle, but I'm not seeing how to do it in mysql.
I've got this:
(please restrain yourself from re-formatting my sql, last time somebody did that they changed it so it wasn't the same and made the question meaningless)
select table1.id
from
table1
inner join
table2 on (table1.id = table2.id and table2.data='cat'),
table1 t1
left outer join
table3 on (t1.id = table3.id and table3.data = 'dog')
And I get all sorts of results that make no sense.
I want to get a list of all of the id's from table1 where table2.data = cat, then do an outer join with the results of that against table 3 where table3.data = dog.
I notice that I can't specify the same table/alias for table1 in the two join clauses, so that leads me to believe that mysql is running the join expressions separately and ORing the results together or something like that.
I also tried getting rid of the "inner join" in the from section and putting it in the where clause, that didn't work either, though it didn't work in a different way (got different erroneous results)
This would be so easy in sybase or oracle.
What am I doing wrong?
select table1.id
from
table1
inner join
table2 on (table1.id = table2.id and table2.data='cat')
left outer join
table3 on (table1.id = table3.id and table3.data = 'dog')
I think you never want to use a comma in the from statement. I believe the comma is equivalent to saying cross join. Not sure though, but I think this query is what you're looking for.
Related
I was reading through some old SQL written for a long-dead project and I came across some SQL code that I can't wrap my head around. It was a join statement that used a condition like so:
SELECT ...
FROM TABLE1
LEFT JOIN TABLE2 ON TABLE1.A = TABLE2.B OR TABLE2.B IN(
SELECT D
FROM TABLE3
WHERE TABLE3.C = TABLE1.A
)
I get the join on TABLE1.A = TABLE2.B, simple enough SQL. But how does the part after the OR work?
How would a join even be performed after checking that IN condition? To my (inexperienced) mind, that seems like poorly structured logic, no?
This question is different than the ones I have seen already answered. Is it possible to left join using multiple 'FROM' tables? When I try it (with other code, but the principle is the same) I get the error 'Unknown column 'table1.otherId' in 'on clause'. Any help would be greatly appreciated.
Something like this:
SELECT *
FROM table1, table2
LEFT JOIN other_table
ON other_table.id = table2.id
AND other_table.otherId = table1.otherId
Try like this:-
SELECT *
FROM table1
LEFT JOIN other_table
ON table1.id=other_table.id LEFT JOIN table2 ON
other_table.otherId = table2.id
It depends what you want to do. You seem to want a Cartesian product of the first two tables with lookups on the third:
SELECT *
FROM table1 CROSS JOIN
table2 LEFT JOIN
other_table
ON other_table.id = table2.id AND
other_table.otherId = table1.otherId;
Commas -- which should just be banned permanently from FROM clauses -- are similar to CROSS JOINs. However, the parsing of the SQL statement is different. A comma prevents the tables before it from being used in ON clauses after it; that is the source of your error.
Answer is "No"
But you can do it this way:
SELECT * FROM table2, other_table ON other_table.id = table2.id
LEFT JOIN table1 ON other_table.otherId = table1.otherId
I don't understand why this query works and what it actually means. It should be noted that this query works when using PDO but doesn't through Mysql cli or even phpmyadmin.
SELECT table1.something, table2.something
FROM someTable
LEFT JOIN table 1
INNER JOIN table2
ON table2.table1_id = table1.id
ON table1.account_id = someTable.account_id
No errors are thrown and, even weirder, I actually have results that are coherent with what the query is supposed to do.
This is valid SQL syntax, assuming you have just taken a snippet from the FROM clause. It is interpreted as:
SELECT table1.something, table2.something
FROM someTable
LEFT JOIN
(table1 INNER JOIN
table2 bbm
ON table2.table1_id = table1.id
)
ON table1.account_id = table2.account_id
That said, this is really arcane, because the alias renames table2 to bbm, which is not used. The ON conditions are only referring to earlier tables. The result is some strange form of CROSS JOIN.
That you can nest JOINs this way should -- in my opinion -- be merely viewed as an amusement. Don't nest JOINs. Each JOIN should be followed by its very own ON clause, before the next table/subquery reference. Nesting joins makes the code is harder to understand. It can introduce errors (which I think happened in this case). There can also be subtle edge cases where it is a little challenging to figure out what is happening.
There are two syntax variations in Standard SQL for writing multiple joins, the common one:
a join b on ... join c on ... join d on ...
and the strange one:
a join b join c join d on ... on ... on ...
In both cases the first ON is processed first, which means the strange syntax joins the first table in the last ON and the last table in the first ON, which is really hard to follow. That's why almost nobody is using it (but some tools might create it)
To change your strange
SELECT table1.something, table2.something
FROM someTable
LEFT JOIN table1
INNER JOIN table2 bbm
ON table2.table1_id = table1.id
ON table1.account_id = someTable.account_id
to the common one move the last ON after the first join:
SELECT table1.something, table2.something
FROM someTable
LEFT JOIN table1
ON table1.account_id = someTable.account_id
INNER JOIN table2 bbm
ON table2.table1_id = table1.id
I am working on some other developers code and need to simplify this query which is in the format below.
SELECT
table1.id, table2.userid, table4.groupid
FROM
table1, table2, table3, table4
WHERE
userid = table4_userid
and
table2.id = table3.table2_id
and
table1.table3_id = table3.id
and
table3.statement_id = 264803
order by table4_groupid
But I am used to join queries by explicitly mentioning the join type i.e. LEFT, RIGHT OR OUTER join. I also use TableName.TableField so that I know which field is from which table. However, as you can see above it's a bit of mix of tablename.tablefield and just tablefield. The above query is working fine but I need to make table4 as a LEFT JOIN so that if there aren't any matching rows in table4 it should still show some data.
My questions are:
1) What types of joins are above?
2) How do I change the above query to make table4 as a LEFT JOIN?
I know you may want the original query but I need just little pointers towards right direction and I will do the rest myself.
Since you are using the tables directly in the where statement, it will be considered ordinary INNER JOINs. Using the where statement for joining table are the old way of joining and much harder to read. If you would like to LEFT JOIN table4, I suggest that you to rewrite the query like this:
SELECT
table1.id,
table2.userid,
table4.groupid
FROM
table1
JOIN table3
ON table1.table3_id = table3.id
JOIN table2
ON table2.id = table3.table2_id
LEFT JOIN table4
ON table2.userid = table4_userid
WHERE
table3.statement_id = 264803
order by
table4_groupid
Looking at the conditions after the WHERE all the above are inner joins.
Try this one, I am not sure of the ONs as we don't really know the tables' structures:
SELECT
t1.id, t2.userid, COALESCE(t4.groupid, 0)
FROM
table1 t1 INNER JOIN table3 t3 ON t1.table3_id=t3.id
INNER JOIN table2 t2 ON t2.id=t3.table2_id
LEFT JOIN table4 t4 ON t1.userid=t4.table4_userid
WHERE
t3.statement_id = 264803
order by t4.groupid
If I want to perform joins on 3 or more tables, what is the best syntax?
This is my attempt:
Select *
from table1
inner join table2 using id1, table2
inner join table3 using id2, table3
inner join table4 using id4
where table2.column1="something"
and table3.column4="something_else";
does that look right? The things I'm not sure about are
1) do I need to seperate the joins with a comma
2) am I right to make all my joins first and then put my conditions after that?
3) would I be better to use sub-queries and if so what is the corect syntax
Thanks for any advice!
Try to avoid using * where possible.
Specify exactly the data you want returned.
Format your queries using a standard style.
Pick a style you like and keep to it.
You will thank yourself later when your queries get more complex.
Most optimizers will recognize when a condition in a WHERE clause implies an INNER JOIN, but there's no reason not to code that explicitly; if nothing else it keeps your WHERE clause manageable.
Be explicit about what columns you join on. Be explicit about the type of join you're using. USING seems like a shortcut that could get you into trouble.
MySQL has traditionally not handled subqueries as well as could be hoped. That may be changing in newer versions, but there are other ways to get your data without relying on them.
Welcome to the wonderful world of relational databases!
select t1.*
, t2.*
, t3.*
, t4.*
from table1 t1
inner join table2 t2
on t1.id = t2.t1_id
and
t2.column1 = "something"
inner join table3 t3
on t2.id = t3.t2_id
and
t3.column4 = "something_else"
inner join table4 t4
on t3.id = t4.t3_id;
1) do I need to seperate the joins with a comma
No
2) am I right to make all my joins first and then put my conditions after that?
Yes
3) would I be better to use sub-queries and if so what is the corect syntax
No. Joining tables is the preferred and correct way.
Joins are not separated by a comma
ANSI syntax puts the joins first then where condition
e.g. SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id WHERE table2.column1='Something'
I'm not 100% sure what you are trying to achieve. But it looks like you do not need to use subqueries.
A subquery would be executed for every row, it sounds as though you could run a more efficient query just using inner joins.
Hope that helps. If you can elaborate a little I will provide more explanation.
Given your requirement that table2 gets joind on the id1-columns in table1 and table2, table3 gets joind on the id2-columns in table2 and table3 and table4 gets joind on the id3-columns in table3 and table4 you'll have to do:
SELECT *
FROM table1
INNER JOIN table2 ON table2.id1 = table1.id1
INNER JOIN table3 ON table3.id2 = table2.id2
INNER JOIN table4 ON table4.id3 = table3.id3
WHERE table2.column1 = "something"
AND table3.column4 = "something_else"
I think this statement is much more clearer on what is exactly joined in which way - compared to the USING-statement.
Remove the comma's and the duplicate table names, like:
Select *
from table1
inner join table2 using id1
inner join table3 using id2
inner join table4 using id4
where table2.column1="something"
and table3.column4="something_else"
If id4 has a different name in table1, explicitly name the join condition, for example:
inner join table4 on table4.id = table1.table4i
You may be able to use natural join which joins on field names common to the tables you want to join as follows.
SELECT *
FROM table1
NATURAL JOIN table2
NATURAL JOIN table3
NATURAL table4
WHERE table2.column1 = "something"
AND table3.column4 = "something_else"