SQL连接:where子句与on子句

读完之后,这不是 显式与隐式SQL联接的重复。 答案可能相关(甚至相同),但问题是不同的。


它们之间有什么区别,应该怎么办?

如果我理解正确,查询优化器应该能够交替使用。

他们不是一回事。

考虑这些查询:

SELECT * FROM Orders LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID WHERE Orders.ID = 12345 

 SELECT * FROM Orders LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID AND Orders.ID = 12345 

第一个将返回订单及其订单号(如果有),订单号12345 。 第二个将返回所有的订单,但只有订单12345将有任何关联的行。

通过INNER JOIN ,这些条款实际上是等价的。 但是,因为它们在function上是一样的,所以它们产生相同的结果,并不意味着这两种子句具有相同的语义。

INNER JOIN它们是可以互换的,优化器会随意重新排列它们。

OUTER JOIN ,它们不一定是可以互换的,取决于它们所依赖的连接的哪一侧。

我把它们放在任何一个地方,这取决于可读性。

  • 内连接无关紧要
  • 外连接的问题

    一个。 WHERE子句:join后。 logging将在join后被过滤。

    ON条款 – join 。 logging(右表)将在join前被过滤。 这可能会结果为null(因为外部连接)。

例如 :考虑下面的表格:

  1. documents: | id | name | --------|-------------| | 1 | Document1 | | 2 | Document2 | | 3 | Document3 | | 4 | Document4 | | 5 | Document5 | 2. downloads: | id | document_id | username | |------|---------------|----------| | 1 | 1 | sandeep | | 2 | 1 | simi | | 3 | 2 | sandeep | | 4 | 2 | reya | | 5 | 3 | simi | 

a)在WHERE子句内:

  SELECT documents.name, downloads.id FROM documents LEFT OUTER JOIN downloads ON documents.id = downloads.document_id WHERE username = 'sandeep' For above query the intermediate join table will look like this. | id(from documents) | name | id (from downloads) | document_id | username | |--------------------|--------------|---------------------|-------------|----------| | 1 | Document1 | 1 | 1 | sandeep | | 1 | Document1 | 2 | 1 | simi | | 2 | Document2 | 3 | 2 | sandeep | | 2 | Document2 | 4 | 2 | reya | | 3 | Document3 | 5 | 3 | simi | | 4 | Document4 | NULL | NULL | NULL | | 5 | Document5 | NULL | NULL | NULL | After applying the `WHERE` clause and selecting the listed attributes, the result will be: | name | id | |--------------|----| | Document1 | 1 | | Document2 | 3 | 

b)内部JOIN子句

  SELECT documents.name, downloads.id FROM documents LEFT OUTER JOIN downloads ON documents.id = downloads.document_id AND username = 'sandeep' For above query the intermediate join table will look like this. | id(from documents) | name | id (from downloads) | document_id | username | |--------------------|--------------|---------------------|-------------|----------| | 1 | Document1 | 1 | 1 | sandeep | | 2 | Document2 | 3 | 2 | sandeep | | 3 | Document3 | NULL | NULL | NULL | | 4 | Document4 | NULL | NULL | NULL | | 5 | Document5 | NULL | NULL | NULL | Notice how the rows in `documents` that did not match both the conditions are populated with `NULL` values. After Selecting the listed attributes, the result will be: | name | id | |------------|------| | Document1 | 1 | | Document2 | 3 | | Document3 | NULL | | Document4 | NULL | | Document5 | NULL | 

在一个内部连接上,他们的意思是一样的。 但是,如果将连接条件放在WHERE和ON子句中,您将在外部连接中获得不同的结果。 看看这个相关的问题和这个答案 (由我)。

我认为最有意义的是总是把连接条件放在ON子句中(除非它是一个外部连接,而实际上你确实希望它在where子句中),因为它使得阅读查询的任何人都更清楚什么条件的表被join,也有助于防止几十行的WHERE子句。

我这样做的方式是:

总是把连接条件放在on子句中如果你正在做一个内连接,所以不要在on子句中添加任何条件,把它们放在where子句中

如果您正在执行左连接,请将任何条件添加到连接右侧的表的on子句中。 这是必须的,因为添加引用连接右侧的where子句将会将连接转换为内部连接(下面将描述一个exception)。

例外情况是,当你正在查找不在特定表中的logging时,你可以将这个参照添加到正确的连接表中的唯一标识符(它永远不为空),以这种方式在where子句中“Where t2。 idfield为空“。 因此,唯一一次应该引用连接右侧的表的方法是find那些不在表中的logging。

这篇文章清楚地解释了这个区别 它还解释了“ON joined_condition vs WHERE joined_condition或者joined_alias为null”。

WHERE子句过滤JOIN的左侧和右侧,而ON子句只会过滤右侧。

  1. 如果你总是想获取左边的行,只有JOIN,如果一些条件匹配,那么你应该ON子句。
  2. 如果要在JOIN完成后过滤双方,则应使用WHERE子句。

就优化器而言,无论您是使用ON还是WHERE定义连接子句,都没有什么区别。

但是,恕我直言,我认为在执行连接时使用ON子句要清楚得多。 这样你有一个特定的部分查询,决定如何处理连接与混合其余的WHERE子句。

当涉及到左连接时, where子句on子句之间有很大的区别。

这里是例子:

 mysql> desc t1; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | | NULL | | | fid | int(11) | NO | | NULL | | | v | varchar(20) | NO | | NULL | | +-------+-------------+------+-----+---------+-------+ 

fid是表t2的id。

 mysql> desc t2; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | | NULL | | | v | varchar(10) | NO | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec) 

查询“on clause”:

 mysql> SELECT * FROM `t1` left join t2 on fid = t2.id AND t1.v = 'K' -> ; +----+-----+---+------+------+ | id | fid | v | id | v | +----+-----+---+------+------+ | 1 | 1 | H | NULL | NULL | | 2 | 1 | B | NULL | NULL | | 3 | 2 | H | NULL | NULL | | 4 | 7 | K | NULL | NULL | | 5 | 5 | L | NULL | NULL | +----+-----+---+------+------+ 5 rows in set (0.00 sec) 

查询“where子句”:

 mysql> SELECT * FROM `t1` left join t2 on fid = t2.id where t1.v = 'K'; +----+-----+---+------+------+ | id | fid | v | id | v | +----+-----+---+------+------+ | 4 | 7 | K | NULL | NULL | +----+-----+---+------+------+ 1 row in set (0.00 sec) 

很显然,第一个查询从t1返回一个logging,并从t2返回从属行,如果有的话,对于行t1.v ='K'。

第二个查询从t1返回行,但只有t1.v ='K'才会有任何关联的行。

为了获得更好的性能,表格应该有一个专门用于JOINS的索引列。

所以如果你的条件列是不是那些索引列之一,那么我怀疑是最好保持它在哪里。

所以你JOIN使用索引列,然后JOIN后运行无索引列的条件。

我认为这是连接序列效应。 在左上连接的情况下,SQL先左连接,然后在哪里过滤。 在downer情况下,首先findOrders.ID = 12345,然后join。

在SQL中,'WHERE'和'ON'子句是条件语句的一种,但它们之间的主要区别在于,在select/更新语句中使用'Where'子句来指定条件,而'ON'子句用于连接中,在连接表之前validation或检查logging是否在目标表和匹配表中匹配

例如: – 'WHERE'

SELECT * FROM employee WHERE employee_id = 101

例如: – “开”

*有两个表employee和employee_details,匹配的列是employee_id *

SELECT * FROM employee INNER JOIN employee_details ON employee.employee_id = employee_details.employee_id

希望我已经回答了你的问题。回复澄清。

对于内部连接, WHEREON可以互换使用。 实际上,可以在相关的子查询中使用ON 。 例如:

 update mytable set myscore=100 where exists ( select 1 from table1 inner join table2 on (table2.key = mytable.key) inner join table3 on (table3.key = table2.key and table3.key = table1.key) ... ) 

这是(恕我直言)完全混淆到人类,很容易忘记将table1链接到任何东西(因为“驱动程序”表没有“on”条款),但它是合法的。

这是我的解决scheme。

 SELECT song_ID,songs.fullname, singers.fullname FROM music JOIN songs ON songs.ID = music.song_ID JOIN singers ON singers.ID = music.singer_ID GROUP BY songs.fullname 

必须有 GROUP BY才能使其工作。

希望这个帮助。