在MySQL JOIN
中,ON
和USING()
有什么区别?据我所知,USING()
只是更方便的语法,而当列名不相同时,ON
允许更多的灵活性。然而,这种差异是如此微小,你认为他们只是取消了USING()
。
除此之外还有更多的东西吗?如果是,我应该在特定情况下使用哪个?
它主要是语法糖,但有几个不同之处值得注意:
ON是两者中较为普遍的。可以在一列,一组列甚至条件上连接表。例如:
SELECT * FROM world.City JOIN world.Country ON (City.CountryCode = Country.Code) WHERE ...
当两个表共享一个与它们连接的完全相同名称的列时,USING很有用。在这种情况下,可以说:
SELECT ... FROM film JOIN film_actor USING (film_id) WHERE ...
另一个好处是,不需要完全限定连接列:
SELECT film.title, film_id -- film_id is not prefixed
FROM film
JOIN film_actor USING (film_id)
WHERE ...
为了说明,要使用ON执行上述操作,我们必须写:
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 ...
请注意film.film_id
条款中的SELECT
资格。仅仅说film_id
是无效的,因为这会造成歧义:
错误1052(23000):字段列表中的列'film_id'不明确
至于select *
,连接列在ON
的结果集中出现两次,而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>
当我发现ON
比USING
更有用时,我想我会在这里筹码。这是当OUTER
加入被引入查询时。
ON
受益于允许在保持OUTER
连接的同时限制查询是OUTER
加入的表的结果集。试图通过指定WHERE
子句来限制结果集,实际上会将OUTER
连接更改为INNER
连接。
当然这可能是一个相对的角落案例。值得把它放在那里.....
例如:
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)
;
Wikipedia有关于USING
的以下信息:
然而,USING结构不仅仅是语法糖,因为结果集与具有显式谓词的版本的结果集不同。具体来说,USING列表中提到的任何列只会出现一次,具有非限定名称,而不是连接中的每个表一次。在上面的例子中,将有一个DepartmentID列,没有employee.DepartmentID或department.DepartmentID。
它正在谈论的表:
Postgres文档也很好地定义了它们:
ON子句是最常见的连接条件:它采用与WHERE子句中使用的布尔值表达式相同的布尔值表达式。如果ON表达式的计算结果为true,则T1和T2中的一对行匹配。
USING子句是一种速记,允许您利用连接的双方对连接列使用相同名称的特定情况。它采用逗号分隔的共享列名列表,并形成一个连接条件,包括每个列的相等比较。例如,用USING(a,b)连接T1和T2产生连接条件ON T1.a = T2.a AND T1.b = T2.b.
此外,JOIN USING的输出会抑制冗余列:不需要打印两个匹配的列,因为它们必须具有相等的值。当JOIN ON生成T1中的所有列,后跟T2中的所有列时,JOIN USING为每个列出的列对(按列出的顺序)生成一个输出列,然后是T1中的任何剩余列,后跟T2中的所有剩余列。
对于那些在phpMyAdmin中进行实验的人来说,只需一句话:
phpMyAdmin似乎与USING
有一些问题。为了记录,这是在Linux Mint上运行的phpMyAdmin,版本:“4.5.4.1deb2ubuntu2”,数据库服务器:“10.2.14-MariaDB-10.2.14 + maria~xenial - mariadb.org二进制分发”。
我在phpMyAdmin和终端(命令行)中使用SELECT
和JOIN
运行USING
命令,而phpMyAdmin中的命令会产生一些令人困惑的响应:
1)最后的LIMIT
条款似乎被忽略了。
2)页面顶部报告的假定行数,结果有时是错误的:例如返回4,但在顶部显示“显示行0 - 24(总共2503,查询耗时0.0018秒。) “
正常登录到mysql并运行相同的查询不会产生这些错误。使用JOIN ... ON ...
在phpMyAdmin中运行相同的查询时也不会发生这些错误。大概是一个phpMyAdmin错误。