311

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

还有比眼前所见的更多吗?如果是,在特定情况下我应该使用哪个?

4

5 回答 5

500

它主要是语法糖,但有几个值得注意的区别:

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>
于 2012-07-06T17:32:51.777 回答
20

当我发现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)
; 
于 2014-09-12T11:15:59.727 回答
19

维基百科有以下信息USING

然而,USING 构造不仅仅是语法糖,因为结果集不同于具有显式谓词的版本的结果集。具体来说,USING 列表中提到的任何列都只会出现一次,名称不合格,而不是为连接中的每个表出现一次。在上述情况下,将有一个 DepartmentID 列,并且没有employee.DepartmentID 或department.DepartmentID。

它正在谈论的表格:

在此处输入图像描述

Postgres文档也很好地定义了它们:

ON 子句是最通用的连接条件:它采用与 WHERE 子句中使用的相同类型的布尔值表达式。如果 ON 表达式的计算结果为真,则 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 中的任何剩余列.

于 2015-07-21T00:25:13.340 回答
6

数据库表

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

SQL USING vs ON 子句表关系

post表有 3 行:

| post_id | title     |
|---------|-----------|
| 1       | Java      |
| 2       | Hibernate |
| 3       | JPA       |

post_comment表有3条记录:

| post_comment_id | review    | post_id |
|-----------------|-----------|---------|
| 1               | Good      | 1       |
| 2               | Excellent | 1       |
| 3               | Awesome   | 2       |

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

传统上,在编写INNER JOINLEFT 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

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

| post_id | title     | review    |
|---------|-----------|-----------|
| 1       | Java      | Good      |
| 1       | Java      | Excellent |
| 2       | Hibernate | Awesome   |

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

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

SELECT
  post_id,
  title,
  review
FROM post
INNER JOIN post_comment USING(post_id)
ORDER BY post_id, post_comment_id

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

| post_id | title     | review    |
|---------|-----------|-----------|
| 1       | Java      | Good      |
| 1       | Java      | Excellent |
| 2       | Hibernate | Awesome   |

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

我们将得到以下结果集:

| post_id | title     | post_comment_id | review    | post_id |
|---------|-----------|-----------------|-----------|---------|
| 1       | Java      | 1               | Good      | 1       |
| 1       | Java      | 2               | Excellent | 1       |
| 2       | Hibernate | 3               | Awesome   | 2       |

如您所见,由于和表都包含一列,所以post_id重复的。postpost_commentpost_id

SQL JOIN USING 子句与SELECT *

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

SELECT *
FROM post
INNER JOIN post_comment USING(post_id)
ORDER BY post_id, post_comment_id

我们将得到以下结果集:

| post_id | title     | post_comment_id | review    |
|---------|-----------|-----------------|-----------|
| 1       | Java      | 1               | Good      |
| 1       | Java      | 2               | Excellent |
| 2       | Hibernate | 3               | Awesome   |

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

结论

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

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

于 2020-07-28T09:47:49.063 回答
1

对于那些在 phpMyAdmin 中进行实验的人,只需一句话:

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

我已经在 phpMyAdmin 和终端(命令行)中SELECT使用JOINand运行命令,USING而 phpMyAdmin 中的命令产生了一些令人费解的响应:

1)LIMIT末尾的一个子句似乎被忽略了。
2) 页面顶部报告的带有结果的假定行数有时是错误的:例如返回 4,但顶部显示“显示第 0 - 24 行(总共 2503 行,查询耗时 0.0018 秒。) "

正常登录 mysql 并运行相同的查询不会产生这些错误。在 phpMyAdmin 中使用JOIN ... ON .... 大概是一个 phpMyAdmin 错误。

于 2018-06-07T21:10:58.557 回答