Mixing ANSI 1992 JOINs and COMMAs in a query - mysql

i'm trying the following MySQL query to fetch some data:
SELECT m.*, t.*
FROM memebers as m, telephone as t
INNER JOIN memeberFunctions as mf ON m.id = mf.memeber
INNER JOIN mitgliedTelephone as mt ON m.id = mt.memeber
WHERE mf.function = 32
But i always get the following error:
#1054 - Unknown column 'm.id' in 'on clause'
The column does exists and the query works fine with only one table (e.g. when i remove telephone)
Does anybody know what I do wrong?

According to this link, you shouldn't mix up both notations when building up joins. The comma you are using to join memebers as m, telephone as t, and the subsequent calls to inner join, are triggering the unknown column error.
To deal with it, use CROSS/INNER/LEFT JOIN instead of commas.
Previously, the comma operator (,) and JOIN both had the same
precedence, so the join expression t1, t2 JOIN t3 was interpreted as
((t1, t2) JOIN t3). Now JOIN has higher precedence, so the expression
is interpreted as (t1, (t2 JOIN t3)). This change affects statements
that use an ON clause, because that clause can refer only to columns
in the operands of the join, and the change in precedence changes
interpretation of what those operands are.
For pedagogic purpose, I'm adding the query as it, I think, should be:
SELECT m.*, t.*
FROM memebers as m
JOIN telephone as t
JOIN memeberFunctions as mf ON m.id = mf.memeber AND mf.function = 32
JOIN mitgliedTelephone as mt ON m.id = mt.memeber
Since you're not joining t and m, the final result will be a cartesian product; you might want it to be revised.
I Hope it helped.

It seems your requirement is to join members table but you are joining with telephone table. just change their order.
SELECT
`m`.*,
`t`.*
FROM
`memebers` AS `m`
JOIN `telephone` AS `t`
JOIN `memeberFunctions` AS `mf`
ON `m`.`id` = `mf`.`memeber`
AND `mf`.`function` = 32
JOIN `mitgliedTelephone` AS `mt`
ON `m`.`id` = `mt`.`memeber`;
Hope this helps you. Thank you!!

Related

How to do multiple joins when some tables are empty

I am trying to append 'lookup data' to a main record text/description field so it looks something like this:
This is the Description Text
LookUpName1:
LookupValue1
LookupValueN
This worked fine with Inner Join like so
Select J.id, Concat('<b>LookUpName</b>:<br>',group_concat(F.LookUpValue SEPARATOR '<br>'))
from MainTable J Inner Join
LookUpTable L Inner Join
LookUpValuesTable F
On J.ID = L.JobID and F.ID = L.FilterID
Group by J.ID
However my goal is to add append multiple Lookup Tables and if I add them to this as Inner Joins I naturally just get those record where both/all the LookupTables have records.
On the other hand when I tried Join or Left Join I got an error on the Group by J.ID.
My goal is to append any of the existing Lookup Table values to all of the Description. Right now all I can achieve is returning appended descriptions which have ALL of the Lookup table values.
Your query would work if the on clauses were in the "right" place:
select J.id,
Concat('<b>LookUpName</b>:<br>', group_concat(F.LookUpValue separator '<br>'))
from MainTable J left join
LookUpTable L
on J.ID = L.JobID left join
LookUpValuesTable F
on F.ID = L.FilterID
group by J.ID;
The problem with your query is a MySQL (mis)feature. The on clause is optional for an inner join. Don't ask me why the MySQL designers thought inner join and cross join should be syntactically equivalent. Every other database requires an on clause for an inner join. It is easy enough to express a cross join using on 1=1.
However, the on clause is required for the left join, so when you switch to a left join, the compiler has a problem with the unorthodox syntax. The real problem is a missing on clause; this just happens to show up as "I wasn't expecting a group by yet." Using more traditional syntax with each join followed by an on should fix the problem.

Inner Join and Cross Join yielding the same result

use classicmodels;
select Orders.OrderNumber,
Customers.CustomerName, Orders.Status, orders.shippeddate,
Customers.Country
from Customers **cross join/inner join** Orders
on Customers.CustomerNumber = Orders.customerNumber
order by 1 asc
Hi all, I'm really confused as to why inner join in my query isn't really any different from the result of the cross join? I thought that cross join would result of a Cartesian product but both joins are giving me 326 rows. I've also seen somewhere that I shouldn't use non-unique data?
From the MySQL JOIN docs:
In MySQL, JOIN, CROSS JOIN, and INNER JOIN are syntactic equivalents
(they can replace each other). In standard SQL, they are not
equivalent. INNER JOIN is used with an ON clause, CROSS JOIN is used
otherwise.

Difference between USING and ON when joining more than two tables

Say I have three tables with the following data in them:
CREATE TABLE movies (
movie_id INT,
movie_name VARCHAR(255),
PRIMARY KEY (movie_id)
);
CREATE TABLE movie_ratings (
movie_rating_id INT,
movie_id INT,
rating_value TINYINT,
PRIMARY KEY (movie_rating_id),
KEY movie_id (movie_id)
);
CREATE TABLE movie_actors (
movie_actor_id INT,
movie_id INT,
actor_id INT,
PRIMARY KEY (movie_actor_id),
KEY movie_id (movie_id)
);
INSERT INTO movies VALUES (1, 'Titanic'),(2,'Star Trek');
INSERT INTO movie_ratings VALUES (1,1,5),(2,1,4),(3,1,5);
INSERT INTO movie_actors VALUES (1,1,2),(2,2,2);
If I wanted to get the average rating and number of actors for each movie, I could do this using JOINs:
SELECT m.movie_name, AVG(rating_value) AS avgRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN movie_ratings r ON m.movie_id = r.movie_id
LEFT JOIN movie_actors a ON m.movie_id = a.movie_id
GROUP BY m.movie_id;
Let's call that query A. Query A can be rewritten with USING thusly:
SELECT m.movie_name, AVG(rating_value) AS avgRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN movie_ratings r USING (movie_id)
LEFT JOIN movie_actors a USING (movie_id)
GROUP BY m.movie_id;
Let's call that query B.
Both of those queries return 1 as numActors for the movie 'Star Trek'. So let's modify that query a bit:
SELECT m.movie_name, AVG(rating_value) AS avgRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN movie_ratings r ON m.movie_id = r.movie_id
LEFT JOIN movie_actors a ON r.movie_id = a.movie_id
GROUP BY m.movie_id;
Let's call this query C. Instead of doing m.movie_id = a.movie_id I'm now doing r.movie_id = a.movie_id. For query C numActors is 0.
My questions are:
How can I write query C using USING? Can I?
Is USING essentially doing an ON with the current table and the table mentioned in FROM?
If the answer to #2 is yes then what does USING do when an implicit JOIN is used and multiple tables are in the FROM?
If the column name is the same in both tables then yes, you can use USING().
In other words, this:
SELECT movie_name, AVG(rating_value) AS averageRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN movie_ratings r ON m.movie_id = r.movie_id
LEFT JOIN movie_actors a ON m.movie_id = a.movie_id
GROUP BY m.movie_id;
Is the same as:
SELECT movie_name, AVG(rating_value) AS averageRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN movie_ratings USING (movie_id)
LEFT JOIN movie_actors USING (movie_id)
GROUP BY movie_id;
As far as the ambiguity there won't be any here. It will join the tables when the movie_id is equal. In your select statement, you are pulling the movie_name, which only exists in one column.
However, if you said this:
SELECT movie_id, AVG(rating_value) AS averageRating, COUNT(actor_id) AS numActors
MySQL will say there is an error because movie_id cannot be resolved because it as ambiguous. To fix this ambiguity, you'd just have to make sure you used a table alias or name when selecting movie_id.
This is a valid select statement:
SELECT m.movie_id, AVG(rating_value) AS averageRating, COUNT(actor_id) AS numActors
No error would be thrown for this.
I would like to comment that I foresee some danger here. If you left join movies with all of these tables, you could potentially receive null values. If movie_id 1 does not have any ratings, your AVG(rating_value) will return null. You won't have this problem for COUNT(actor_id) as this will just return 0. I don't know if this bothers you, but be aware that that column could return null.
I built the sample tables in MySQL workbench, and I'm unable to get SQL Fiddle to work to show you, but if you would like to see the data I've created let me know and I will edit the question.
1. Can C be rewritten using USING?
Yes, you can, using a nested join:
SELECT m.movie_name, AVG(rating_value) AS avgRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN (
movie_ratings r
LEFT JOIN movie_actors a USING (movie_id)
) USING (movie_id)
GROUP BY m.movie_id
2. Is USING essentially doing an ON with the current table and the table mentioned in FROM?
No. MySQL Documentation says:
The evaluation of multi-way natural joins differs in a very important way that affects the result of NATURAL or USING joins and that can require query rewriting. Suppose that you have three tables t1(a,b), t2(c,b), and t3(a,c) that each have one row: t1(1,2), t2(10,2), and t3(7,10). Suppose also that you have this NATURAL JOIN on the three tables:
SELECT ... FROM t1 NATURAL JOIN t2 NATURAL JOIN t3;
Previously, the left operand of the second join was considered to be t2, whereas it should be the nested join (t1 NATURAL JOIN t2). As a result, the columns of t3 are checked for common columns only in t2, and, if t3 has common columns with t1, these columns are not used as equi-join columns. Thus, previously, the preceding query was transformed to the following equi-join:
SELECT ... FROM t1, t2, t3
WHERE t1.b = t2.b AND t2.c = t3.c;
So basically, in older versions of MySQL your query B was not the same as query A, but as query C!
3. What does USING do when an implicit JOIN is used and multiple tables are in the FROM?
Again, citing the MySQL Documentation:
Previously, the comma operator (,) and JOIN both had the same precedence, so the join expression t1, t2 JOIN t3 was interpreted as ((t1, t2) JOIN t3). Now JOIN has higher precedence, so the expression is interpreted as (t1, (t2 JOIN t3)). This change affects statements that use an ON clause, because that clause can refer only to columns in the operands of the join, and the change in precedence changes interpretation of what those operands are.
It's all about join-order and precedence. So basically t1, t2 JOIN t3 USING (x) would do t2 JOIN t3 USING(x) first and join that with t1.
There is no ambiguity as USING applies to the tables in the join so this query
SELECT movie_name, AVG(rating_value), COUNT(actor_id)
FROM movies m
LEFT JOIN movie_ratings r USING (movie_id)
LEFT JOIN movie_actors a USING (movie_id)
GROUP BY m.movie_id;
is pretty much equivalent to the one with inner joins except that the movie_idcolumn should only appear once in the results, instead of three times in theinner joincase.
See this example for the column elimination: http://ideone.com/qMj5XK (using SQLite I think, SQL Fiddle wouldn't work but MySQL should behave in the same way).
How can I write query C using USING? Can I?
Like jpw mentionned in is answer yes you can use USING with query C. It will join m with rusing movie_id and m with a also using movie_id. In fact USING with MySQL is aligned with the SQL 2003 standard.
Is USING essentially doing an ON with the current table and the table
mentioned in FROM?
Yes USING is doing an ON with the current table and the table mentioned in the FROM clause. The only difference is the number columns you are going to end with if you use an asterisk in the SELECT clause. The Oracle documentation for USING is much more helpful than the MySQL documentation about that.
If the answer to #2 is yes then what does USING do when an implicit
JOIN is used and multiple tables are in the FROM?
You can try it for yourself but I'm pretty sure it wouldn't work with an implicit join (FROM tableA, tableB). This might be just another reason why implicit joins should be avoided.
Also since USING can only be used with explicit join that would mean a very awkward query mixing both explicit and implicit join. Something you probably want to avoid.
Edit :
By the way, numActors is 0 in query C because your join are incorrect. In fact if there are no movie rating then there are no actors! If you fix that you should get the same result than query B.
SELECT m.movie_name, AVG(rating_value) AS avgRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN movie_ratings r ON m.movie_id = r.movie_id
LEFT JOIN movie_actors a ON m.movie_id = a.movie_id -- Instead of r.movie_id = a.movie_id
GROUP BY m.movie_id;

mysql SELECT FROM two tables and LEFT JOIN

I have problem with select from two tables and left join to third. Query:
SELECT
c.id AS currency, u.user, us.enabled AS currency
FROM
users AS u,
currency AS c
LEFT JOIN users_settings AS us ON(c.id=us.currency, u.user=us.user)
WHERE
c.off=0 AND c.disabled=0 AND c.status=1
Error:
#1054 - Unknown column 'u.user' in 'field list'
I need Cartesian product of users and currency.
Users: id, login, email, pass
http://en.wikipedia.org/wiki/Cartesian_product
You are mixing explicit and implicit join syntax. Try this:
SELECT c.id AS currency, u.user, us.enabled AS currency
FROM currency AS c LEFT JOIN
users_settings AS us
ON c.id = us.currency LEFT JOIN
users u
on u.user = us.user
WHERE c.off = 0 AND c.disabled = 0 AND c.status = 1 ;
MySQL does not necessarily allow the fields to be known over a ,. Scoping is one of the differences between , and cross join. In any case, though, you should use a separate on clause for each join.
Here is the description in the documentation:
INNER JOIN and , (comma) are semantically equivalent in the absence of
a join condition: both produce a Cartesian product between the
specified tables (that is, each and every row in the first table is
joined to each and every row in the second table).
However, the precedence of the comma operator is less than of INNER
JOIN, CROSS JOIN, LEFT JOIN, and so on. If you mix comma joins with
the other join types when there is a join condition, an error of the
form Unknown column 'col_name' in 'on clause' may occur. Information
about dealing with this problem is given later in this section.
Instead of trying to really understand what this means, just avoid using , in the from clause. It is not ever needed.

MySQL - SELECT with LEFT JOIN optimization

I have 3 tables to select from. 2 of them are always necessary (tbl_notes, tbl_clients) while the 3rd is optional (tbl_notes_categories).
I've always used a LEFT JOIN in my queries with questionable correlating records to the primary table.
But I'm not getting any results with the query below.
Would someone point out how I'm using the LEFT JOIN incorrectly?
SELECT n.*, c.clientname, nc.notecategoryname
FROM tbl_notes n, tbl_clients c
LEFT JOIN tbl_notes_categories nc ON n.categoryid = nc.categoryid
WHERE n.clientid = c.clientid
AND c.clientid = 12345
ORDER BY n.dateinserted DESC
In fact, I'm getting a sql error.
#1054 - Unknown column 'n.categoryid' in 'on clause'
categoryid certainly does exist in tbl_notes
I probably need to brush up on how JOINS really work. I'm guessing I cannot have a LEFT JOIN with 2 database tables before it?
On a side note, I can foresee times when there will be multiple required tables, with several optional tables. (in this case tbl_notes_categories is optional)
Assuming the column categoryid exists in the tbl_notes table...
Try rewriting the query to use the JOIN syntax, rather than using the old-school comma as the join operator. (If the problem isn't a misnamed column, I suspect the problem is in mixing the two types of syntax... but this is just a suspicion, I have no reason to test mixing old-style comma joins with JOIN keywords.)
I'd write the statement like this:
SELECT n.*, c.clientname, nc.notecategoryname
FROM tbl_notes n
JOIN tbl_clients c
ON n.clientid = c.clientid
LEFT
JOIN tbl_notes_categories nc
ON nc.categoryid = n.categoryid
WHERE c.clientid = 12345
ORDER BY n.dateinserted DESC
(Actually, I would specify the individual columns to return from n, rather than using n.*, but that's just a style preference, not a SQL syntax requirement.)