MySQL ON vs USING?

Nat*_*ael 243 mysql join using

在MySQL中JOIN,ON和之间有什么区别USING()?据我所知,USING()只是更方便的语法,而ON当列名不相同时允许更多的灵活性.然而,这种差异是如此微小,你会认为他们只是消失了USING().

除此之外还有更多的东西吗?如果是,我应该在特定情况下使用哪个?

Shl*_*ach 378

它主要是语法糖,但有几个不同之处值得注意:

ON是两者中较为普遍的.可以在一列,一组列甚至条件上连接表.例如:

SELECT * FROM world.City JOIN world.Country ON (City.CountryCode = Country.Code) WHERE ...
Run Code Online (Sandbox Code Playgroud)

当两个表共享一个与它们连接的完全相同名称的列时,USING很有用.在这种情况下,可以说:

SELECT ... FROM film JOIN film_actor USING (film_id) WHERE ...
Run Code Online (Sandbox Code Playgroud)

另一个好处是,不需要完全限定连接列:

SELECT film.title, film_id -- film_id is not prefixed
FROM film
JOIN film_actor USING (film_id)
WHERE ...
Run Code Online (Sandbox Code Playgroud)

为了说明,要使用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 ...
Run Code Online (Sandbox Code Playgroud)

请注意film.film_idSELECT条款中的资格.如果说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>
Run Code Online (Sandbox Code Playgroud)

  • 实际上,两者都解释为普通的老式Theta风格.您可以通过在查询中调用EXPLAIN EXTENDED,然后显示SHOW WARNINGS来查看. (8认同)
  • @PhoneixS它在[ANSI SQL 92标准]中(http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt) (4认同)
  • +1关于语法差异的好答案.我对性能差异感到好奇,如果有的话.我想象`USING`解释为'ON`. (2认同)
  • 你也可以做`USING(`category`,`field_id`)`这在通过复合主键连接时很有用,我也听说*优化器在某些情况下使用`USING`来提高性能 (2认同)
  • “USING”是 MySQL 定义还是标准定义? (2认同)

Tom*_*Mac 15

当我发现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)
; 
Run Code Online (Sandbox Code Playgroud)

  • 非常好点.在`using`提供的所有优点中,它不能与其他谓词组合:`select*from t join t2 using(i)和on 1`将无法工作. (4认同)

Vla*_*cea 12

数据库表

为了演示 USING 和 ON 子句的工作原理,我们假设有以下post数据库表,它们通过表中的外键列引用表中的主键列post_comment形成一对多表关系:post_idpost_commentpost_idpost

SQL USING 与 ON 子句表关系

post表有 3 行:

| post_id | title     |
|---------|-----------|
| 1       | Java      |
| 2       | Hibernate |
| 3       | JPA       |
Run Code Online (Sandbox Code Playgroud)

post_comment表有3条记录:

| post_comment_id | review    | post_id |
|-----------------|-----------|---------|
| 1               | Good      | 1       |
| 2               | Excellent | 1       |
| 3               | Awesome   | 2       |
Run Code Online (Sandbox Code Playgroud)

使用自定义投影的 JOIN ON 子句

传统上,在编写INNER JOINorLEFT JOIN查询时,我们碰巧使用 ON 子句来定义连接条件。

例如,要获取评论及其关联的帖子标题和标识符,我们可以使用以下 SQL 投影查询:

SELECT
   post.post_id,
   title,
   review
FROM post
INNER JOIN post_comment ON post.post_id = post_comment.post_id
ORDER BY post.post_id, post_comment_id
Run Code Online (Sandbox Code Playgroud)

并且,我们得到以下结果集:

| post_id | title     | review    |
|---------|-----------|-----------|
| 1       | Java      | Good      |
| 1       | Java      | Excellent |
| 2       | Hibernate | Awesome   |
Run Code Online (Sandbox Code Playgroud)

使用自定义投影的 JOIN USING 子句

当外键列和它引用的列具有相同的名称时,我们可以使用 USING 子句,如下例所示:

SELECT
  post_id,
  title,
  review
FROM post
INNER JOIN post_comment USING(post_id)
ORDER BY post_id, post_comment_id
Run Code Online (Sandbox Code Playgroud)

而且,此特定查询的结果集与之前使用 ON 子句的 SQL 查询相同:

| post_id | title     | review    |
|---------|-----------|-----------|
| 1       | Java      | Good      |
| 1       | Java      | Excellent |
| 2       | Hibernate | Awesome   |
Run Code Online (Sandbox Code Playgroud)

USING 子句适用于 Oracle、PostgreSQL、MySQL 和 MariaDB。SQL Server 不支持 USING 子句,因此您需要使用 ON 子句。

USING 子句可与 INNER、LEFT、RIGHT 和 FULL JOIN 语句一起使用。

SQL JOIN ON 子句与SELECT *

现在,如果我们更改之前的 ON 子句查询以使用以下命令选择所有列SELECT *

SELECT *
FROM post
INNER JOIN post_comment ON post.post_id = post_comment.post_id
ORDER BY post.post_id, post_comment_id
Run Code Online (Sandbox Code Playgroud)

我们将得到以下结果集:

| post_id | title     | post_comment_id | review    | post_id |
|---------|-----------|-----------------|-----------|---------|
| 1       | Java      | 1               | Good      | 1       |
| 1       | Java      | 2               | Excellent | 1       |
| 2       | Hibernate | 3               | Awesome   | 2       |
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,post_id重复的,因为postpost_comment表都包含一post_id列。

SQL JOIN USING 子句与SELECT *

另一方面,如果我们运行一个SELECT *包含 USING 子句作为 JOIN 条件的查询:

SELECT *
FROM post
INNER JOIN post_comment USING(post_id)
ORDER BY post_id, post_comment_id
Run Code Online (Sandbox Code Playgroud)

我们将得到以下结果集:

| post_id | title     | post_comment_id | review    |
|---------|-----------|-----------------|-----------|
| 1       | Java      | 1               | Good      |
| 1       | Java      | 2               | Excellent |
| 2       | Hibernate | 3               | Awesome   |
Run Code Online (Sandbox Code Playgroud)

您可以看到,这次该列已进行重复数据删除,因此结果集中包含post_id一列。post_id

结论

如果数据库模式的设计使得外键列名与它们引用的列相匹配,并且 JOIN 条件仅检查外键列值是否等于另一个表中其镜像列的值,那么您可以使用 USING条款。

否则,如果外键列名称与引用列不同或者您想要包含更复杂的联接条件,则应改用 ON 子句。


Rob*_*cha 9

维基百科有以下信息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中的所有剩余列.