MySQL ON与USING?


252

在MySQL中JOINON和之间有什么区别USING()?据我所知,USING()只是语法更方便,而ON当列名不相同时,则允许更多的灵活性。但是,这种差别是如此之小,您可能会认为他们只是取消了USING()

除了眼球以外,还有什么呢?如果是,在给定情况下应该使用哪个?



请注意,using除了连接外还有其他用法。请参阅stackoverflow.com/a/13750399/632951
Pacerier

Answers:


400

它主要是语法糖,但是有一些区别值得注意:

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>

2
+1关于语法差异的不错答案。我对性能差异(如果有)感到好奇。我想象会USING解释为ON
杰森·麦克雷里

9
实际上,两者都解释为普通的Theta风格。您可以通过在查询中调用EXPLAIN EXTENDED来查看,然后显示SHOW WARNINGS。
Shlomi Noach

2
您也可以执行USING(类别,field_id ),该类别在通过复合主键进行连接时非常有用,而且我听说优化器确实USING在某些情况下用于提高性能
Timo Huovinen 2013年

USINGMySQL定义还是标准?
PhoneixS

5
@PhoneixS它符合ANSI SQL 92标准
Shlomi Noach

18

当我发现ON比有用的时候,我想我会介入的USING。这是当OUTER连接被引入查询。

ON受益于允许OUTER在保留联接的同时限制查询所联接的表的结果集OUTER。尝试通过指定WHERE子句来限制结果集将有效地将联接更改OUTERINNER联接。

当然,这可能是一个相对极端的情况。值得放在那里.....

例如:

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)
; 

4
非常好点。在using提供的所有优势中,它不能与其他谓词结合使用:无效select*from t join t2 using(i) and on 1
Pacerier,2015年

where hasAirport ;- 这是什么意思 ?没有价值可与进行比较。
Istiaque Ahmed

另请注意,您可以使用ON进行比较,而不仅仅是=。Like SELECT * FROM country LEFT JOIN city ON country.countryId=city.countryId AND city.city BETWEEN 'C' AND 'E' 将列出所有国家,但仅列出以C或D开头的城市(如果有)。(加上称为“ E”的城镇)
Roemer

我什至在ON子查询中甚至进行了JOIN !!! 一切皆有可能,有时甚至非常有效。
Roemer

11

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的所有剩余列。


1

对于那些在phpMyAdmin中尝试此操作的人,只需说一句话:

phpMyAdmin似乎有一些问题USING。作为记录,这是在Linux Mint上运行的phpMyAdmin,版本:“ 4.5.4.1deb2ubuntu2”,数据库服务器:“ 10.2.14-MariaDB-10.2.14 + maria〜xenial-mariadb.org二进制分发版”。

我在phpMyAdmin和Terminal(命令行)中都SELECT使用JOINUSING来运行命令,而phpMyAdmin中的命令会产生一些令人困惑的响应:

1)最后一个LIMIT子句似乎被忽略。
2)有时在页面顶部报告的行数与结果有时是错误的:例如,返回4,但在顶部显示“显示0至24行(共2503行,查询花费0.0018秒。)。 ”

正常登录到mysql并运行相同的查询不会产生这些错误。当使用phpMyAdmin运行相同的查询时,也不会发生这些错误JOIN ... ON ...。大概是phpMyAdmin错误。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.