在 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)
;
维基百科有以下信息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 中的任何剩余列.
为了演示 USING 和 ON 子句如何工作,假设我们有以下post
和数据库表,它们通过表中的外键列引用表中的主键列post_comment
形成一对多的表关系:post_id
post_comment
post_id
post
父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 |
传统上,在编写INNER JOIN
或LEFT 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 |
当外键列和它引用的列同名时,我们可以使用 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 语句一起使用。
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
是重复的。post
post_comment
post_id
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 子句。
对于那些在 phpMyAdmin 中进行实验的人,只需一句话:
phpMyAdmin 似乎有一些问题USING
。作为记录,这是在 Linux Mint 上运行的 phpMyAdmin,版本:“4.5.4.1deb2ubuntu2”,数据库服务器:“10.2.14-MariaDB-10.2.14+maria~xenial - mariadb.org 二进制发行版”。
我已经在 phpMyAdmin 和终端(命令行)中SELECT
使用JOIN
and运行命令,USING
而 phpMyAdmin 中的命令产生了一些令人费解的响应:
1)LIMIT
末尾的一个子句似乎被忽略了。
2) 页面顶部报告的带有结果的假定行数有时是错误的:例如返回 4,但顶部显示“显示第 0 - 24 行(总共 2503 行,查询耗时 0.0018 秒。) "
正常登录 mysql 并运行相同的查询不会产生这些错误。在 phpMyAdmin 中使用JOIN ... ON ...
. 大概是一个 phpMyAdmin 错误。