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子句只会过滤右侧。
- 如果你总是想获取左边的行,只有JOIN,如果一些条件匹配,那么你应该ON子句。
- 如果要在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
希望我已经回答了你的问题。回复澄清。
对于内部连接, WHERE
和ON
可以互换使用。 实际上,可以在相关的子查询中使用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
才能使其工作。
希望这个帮助。