In a MySQL JOIN
, what is the difference between ON
and USING()
? As far as I can tell, USING()
is just more convenient syntax, whereas ON
allows a little more flexibility when the column names are not identical. However, that difference is so minor, you'd think they'd just do away with USING()
.
Is there more to this than meets the eye? If yes, which should I use in a given situation?
In general, we use ON in MySQL. In Joins, we use ON in a set of columns. USING is useful when both the tables share a column of the exact same name on which they join.
In a nutshell, you use ON for most things, but USING is a handy shorthand for the situation where the column names are the same. The example above uses the ON keyword, but since the columns we use to join are called owners_id in both tables, then we can instead put in USING as a shorthand.
The main difference between USING and ON in a join condition is that when SELECT * is used in a query with a USING join, the resulting table will only have one instance of the column specified in the USING condition.
It is mostly syntactic sugar, but a couple differences are noteworthy:
ON is the more general of the two. One can join tables ON a column, a set of columns and even a condition. For example:
SELECT * FROM world.City JOIN world.Country ON (City.CountryCode = Country.Code) WHERE ...
USING is useful when both tables share a column of the exact same name on which they join. In this case, one may say:
SELECT ... FROM film JOIN film_actor USING (film_id) WHERE ...
An additional nice treat is that one does not need to fully qualify the joining columns:
SELECT film.title, film_id -- film_id is not prefixed FROM film JOIN film_actor USING (film_id) WHERE ...
To illustrate, to do the above with ON, we would have to write:
SELECT film.title, film.film_id -- film.film_id is required here FROM film JOIN film_actor ON (film.film_id = film_actor.film_id) WHERE ...
Notice the film.film_id
qualification in the SELECT
clause. It would be invalid to just say film_id
since that would make for an ambiguity:
ERROR 1052 (23000): Column 'film_id' in field list is ambiguous
As for select *
, the joining column appears in the result set twice with ON
while it appears only once with USING
:
mysql> create table t(i int);insert t select 1;create table t2 select*from t; Query OK, 0 rows affected (0.11 sec) Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 Query OK, 1 row affected (0.19 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> select*from t join t2 on t.i=t2.i; +------+------+ | i | i | +------+------+ | 1 | 1 | +------+------+ 1 row in set (0.00 sec) mysql> select*from t join t2 using(i); +------+ | i | +------+ | 1 | +------+ 1 row in set (0.00 sec) mysql>
Thought I would chip in here with when I have found ON
to be more useful than USING
. It is when OUTER
joins are introduced into queries.
ON
benefits from allowing the results set of the table that a query is OUTER
joining onto to be restricted while maintaining the OUTER
join. Attempting to restrict the results set through specifying a WHERE
clause will, effectively, change the OUTER
join into an INNER
join.
Granted this may be a relative corner case. Worth putting out there though.....
For example:
CREATE TABLE country ( countryId int(10) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, country varchar(50) not null, UNIQUE KEY countryUIdx1 (country) ) ENGINE=InnoDB; insert into country(country) values ("France"); insert into country(country) values ("China"); insert into country(country) values ("USA"); insert into country(country) values ("Italy"); insert into country(country) values ("UK"); insert into country(country) values ("Monaco"); CREATE TABLE city ( cityId int(10) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, countryId int(10) unsigned not null, city varchar(50) not null, hasAirport boolean not null default true, UNIQUE KEY cityUIdx1 (countryId,city), CONSTRAINT city_country_fk1 FOREIGN KEY (countryId) REFERENCES country (countryId) ) ENGINE=InnoDB; insert into city (countryId,city,hasAirport) values (1,"Paris",true); insert into city (countryId,city,hasAirport) values (2,"Bejing",true); insert into city (countryId,city,hasAirport) values (3,"New York",true); insert into city (countryId,city,hasAirport) values (4,"Napoli",true); insert into city (countryId,city,hasAirport) values (5,"Manchester",true); insert into city (countryId,city,hasAirport) values (5,"Birmingham",false); insert into city (countryId,city,hasAirport) values (3,"Cincinatti",false); insert into city (countryId,city,hasAirport) values (6,"Monaco",false); -- Gah. Left outer join is now effectively an inner join -- because of the where predicate select * from country left join city using (countryId) where hasAirport ; -- Hooray! I can see Monaco again thanks to -- moving my predicate into the ON select * from country co left join city ci on (co.countryId=ci.countryId and ci.hasAirport) ;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With