在 SQL/MySQL 中,join 语句中的“ON”和“WHERE”有啥区别?

Posted

技术标签:

【中文标题】在 SQL/MySQL 中,join 语句中的“ON”和“WHERE”有啥区别?【英文标题】:In SQL / MySQL, what is the difference between "ON" and "WHERE" in a join statement?在 SQL/MySQL 中,join 语句中的“ON”和“WHERE”有什么区别? 【发布时间】:2011-02-12 22:44:22 【问题描述】:

以下语句给出相同的结果(一个使用on,另一个使用where):

mysql> select * from gifts INNER JOIN sentGifts ON gifts.giftID = sentGifts.giftID;
mysql> select * from gifts INNER JOIN sentGifts WHERE gifts.giftID = sentGifts.giftID;

我只能在左外连接的情况下看到“不匹配”的情况: (找出从未有人送过的礼物)

mysql> select name from gifts LEFT OUTER JOIN sentgifts 
           ON gifts.giftID = sentgifts.giftID 
           WHERE sentgifts.giftID IS NULL;

在这种情况下,它首先使用on,然后是whereon 是否首先进行匹配,然后 where 进行“二级”过滤?还是有更一般的使用onwhere 的规则?谢谢。

【问题讨论】:

这个问题有两个更好的标题。 【参考方案1】:

ON 子句定义了表之间的关系。

WHERE 子句描述了您感兴趣的行。

很多时候你可以交换它们并且仍然得到相同的结果,但是左外连接并不总是这样。

如果ON 子句失败,您仍然会得到一行,其中包含来自 左表,但右表的列中有空值。 如果 WHERE 子句失败,您将根本无法获得该行。

【讨论】:

【参考方案2】:

WHERE 是整个 SELECT 查询的一部分,ON 是每个单独联接的一部分。

ON只能引用以前使用过的表的字段。

当左表中的记录没有实际匹配时,LEFT JOIN 从右表返回一条记录,所有字段都设置为NULLSWHERE 子句然后评估并过滤它。

在您的查询中,仅返回来自 gifts 的记录,而 'sentgifts' 中不匹配。

这是一个例子

gifts

1   Teddy bear
2   Flowers

sentgifts

1   Alice
1   Bob

---
SELECT  *
FROM    gifts g
LEFT JOIN
        sentgifts sg
ON      g.giftID = sg.giftID

---

1  Teddy bear   1     Alice
1  Teddy bear   1     Bob
2  Flowers      NULL  NULL    -- no match in sentgifts

---
SELECT  *
FROM    gifts g
LEFT JOIN
        sentgifts sg
ON      g.giftID = sg.giftID
WHERE   sg.giftID IS NULL

---

2  Flowers      NULL  NULL    -- no match in sentgifts

如您所见,没有实际匹配的人可以在sentgifts.id 中留下NULL,因此只会退回从未发送过的礼物。

【讨论】:

【参考方案3】:

当使用INNER JOINONWHERE 将得到相同的结果。所以,

select *
from Table1 t1
inner join Table2 t2 on t1.id = t2.id
where t1.Name = 'John'

将具有与

完全相同的输出
select *
from Table1 t1
inner join Table2 t2 on t1.id = t2.id
    and t1.Name = 'John'

正如您所指出的,使用OUTER JOIN 时并非如此。构建的查询计划取决于数据库平台和查询细节,并且可能会发生变化,因此仅在此基础上做出决策并不能提供有保证的查询计划。

根据经验,您应该使用在ON 子句中连接表的列和在WHERE 子句中用于过滤的列。这提供了最佳的可读性。

【讨论】:

对比 field1=field2 更复杂的东西使用“ON”是否正确? 是的,经常有多列ON子句。 我的意思是,除了列比较之外,您可以使用复杂的表达式吗? @skan 是的,您可以使用 ON 包含任何条件表达式【参考方案4】:

虽然结果相同,但“ON”先进行连接,然后检索连接集的数据。检索速度更快,负载更少。但是使用 'WHERE' 会导致首先获取两个结果集,然后再应用条件。所以你知道什么是首选。

【讨论】:

【参考方案5】: ON 应用于用于创建每个记录的排列的集合作为 JOIN 操作的一部分 WHERE 指定 JOIN 操作之后应用的过滤器

实际上,ON 将每个不满足其条件的字段替换为 NULL。给定the example by @Quassnoi

gifts

1   Teddy bear
2   Flowers

sentgifts

1   Alice
1   Bob

---
SELECT  *
FROM    gifts g
LEFT JOIN
        sentgifts sg
ON      g.giftID = sg.giftID

---

如果没有 ON 条件,则会为以下集合计算 LEFT JOIN 排列:

'Teddy bear': 'ALICE', 'Bob', 'Flowers': 'ALICE', 'Bob'

g.giftID = sg.giftID ON 条件下,这是将用于创建排列的集合:

'Teddy bear': 'ALICE', 'Bob', 'Flowers': NULL, NULL

实际上是:

'Teddy bear': 'ALICE', 'Bob', 'Flowers': NULL

因此导致左连接:

Teddy bear Alice
Teddy bear Bob
Flowers    NULL

对于 FULL OUTER JOIN,您将拥有:

'Teddy bear': 'ALICE', 'Bob', 'Flowers': NULL 用于左连接, 'ALICE': 'Teddy bear', NULL, 'Flowers': 'Teddy bear', NULL 用于右连接:

Teddy bear Alice
Teddy bear Bob
Flowers    NULL

如果你也有ON g.giftID = 1这样的条件,那就是

NULL: 'ALICE', 'Bob', 'Flowers': NULL

对于 LEFT JOIN 会导致

Flowers NULL

对于 FULL OUTER JOIN 会导致 NULL: 'ALICE', 'Bob', 'Flowers': NULL 用于左连接, 'ALICE': NULL, NULL, 'Flowers': NULL, NULL 用于右连接

NULL    Alice
NULL    Bob
Flowers NULL

注意 MySQL 没有 FULL OUTER JOIN,需要将 UNION 应用于 LEFT JOIN 和 RIGHT JOIN

【讨论】:

【参考方案6】:

如果您使用 JOIN,则需要指定您要加入的条件。该列表位于 ON 子句中。 WHERE 子句用于为查询中的任何位置设置数据条件。

【讨论】:

以上是关于在 SQL/MySQL 中,join 语句中的“ON”和“WHERE”有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

sql语句中的full join具体是怎么回事啊?

SQL语句中的join只能与on连用吗?有没有只用join的?举个例子行吗?

SQL语句中LEFT JOIN和RIGHT JOIN 以及INNER JOIN的区别

常用sql(mysql)语句

SQL MySql与SqlServer差异比较

Join语句中的on和where条件过滤的区别