SQL join: where clause vs. on clause
在读取之后,这不是显式和隐式SQL联接的副本。答案可能是相关的(甚至是相同的),但问题是不同的。
有什么区别?每个都应该有什么区别?
如果我正确理解这一理论,查询优化器应该能够同时使用这两种方法。
他们不是一回事。
考虑以下问题:
1 2 3 4 | SELECT * FROM Orders LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID WHERE Orders.ID = 12345 |
和
1 2 3 4 | SELECT * FROM Orders LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID AND Orders.ID = 12345 |
号
第一个将返回订单及其行(如果有),用于订单号
使用
- 内部连接不重要
外部连接事项
A.
WHERE 条款:加入后。连接发生后将筛选记录。b.
ON 条款-加入前。连接前将筛选记录(来自右表)。这可能会在结果中结束为空(因为外部联接)。
示例:考虑下表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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)在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 | |
。
在
在
我根据可读性将它们放在任何一个地方。
我的做法是:
如果要执行
INNER JOIN ,请始终将连接条件放在ON 子句中。因此,不要在ON条款中添加任何WHERE条件,将它们放在WHERE 条款中。如果要执行
LEFT JOIN 操作,请在ON 子句中为联接右侧的表添加任何where条件。这是必须的,因为添加引用联接右侧的WHERE子句会将联接转换为内部联接。例外情况是当您在查找不在特定表中的记录时。您可以这样将对右联接表中唯一标识符的引用添加到WHERE子句中:
WHERE t2.idfield IS NULL 。因此,您应该引用联接右侧的表的唯一时间是查找那些不在表中的记录。
在内部连接上,它们的含义相同。但是,在外部联接中会得到不同的结果,这取决于您是否将联接条件放在WHERE和ON子句中。看看这个相关的问题和答案(由我)。
我认为习惯于总是把连接条件放在ON子句中是最有意义的(除非它是一个外部连接,而实际上您确实希望它放在WHERE子句中),因为它使阅读您的查询的任何人都能更清楚地了解表连接的条件,而且它还有助于防止WHERE子句成为许多LIN很长。
这篇文章清晰地解释了区别。It also explains the"on joined u condition vs where joined u condition or joined n's null."
在该条款过滤从条款到附录的结果时,该条款被用来产生从条款到附录表之间的表格。
在条款的位置与条款的位置之间有很大的差别,当它来到左边。
这是一个例子:
ZZU1
There fid is id of table t2.
1 2 3 4 5 6 7 8 | 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) |
Query on"on clause":
1 2 3 4 5 6 7 8 9 10 11 12 | 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) |
Query on"where clause":
1 2 3 4 5 6 7 | 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返回一个记录,如果有的话,从T2返回一个记录。
第二个从T1返回的路径,但只为T1.V=K will have any return row with it.
在优化器方面,用on或where定义联接子句不会有什么不同。
但是,imho,我认为在执行连接时使用on子句要清楚得多。这样,您就有了一个查询的特定部分,该部分指示如何处理联接,而不是与其余的WHERE子句混合。
我认为这是连接序列效应。在左上联接的情况下,SQL首先执行左联接,然后执行where筛选器。在downer的情况下,首先查找orders.id=12345,然后执行join。
对于一个内在连接,
1 2 3 4 5 6 7 8 9 10 | 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) ... ) |
This is(IMHO)otterly confusing to a human,and it's very easy to forget to link
您试图加入数据还是过滤数据?
对于可读性,将这些用例分别隔离到on和where是最有意义的。
- 在上加入数据
- 在其中筛选数据
在WHERE子句中存在联接条件和筛选条件的情况下,读取查询可能会变得非常困难。
从性能上看,您不应该看到差异,尽管不同类型的SQL有时处理查询计划的方式不同,因此值得尝试
另外,正如其他人所指出的,如果使用外部联接,那么如果将筛选条件放在ON子句中,则会得到不同的结果,因为它只影响其中一个表。
我在这里写了一篇更深入的文章:https://dataschool.com/learn/difference-between-where-and-on-in-sql
对于更好的性能表,应该有一个特殊的索引柱用于加入。
所以,如果你的条件不是指数柱中的一个,那么我怀疑它最好保持在哪里。
所以你用指数柱加入,然后加入到非指数柱上的条件。
通常,过滤是在两个表格中的一个条款已经结合的地方进行的。有可能,尽管你可能想在他们进来之前过滤一张或两张桌子。I.E.The where clause applies to the whole result set whereas the on clause only applies to the join in question.
在SQL中,"where"和"on"子句是一种条件语句,但它们之间的主要区别是,在select/update语句中使用"where"子句指定条件,而在join中使用"on"子句,在join中验证或检查目标表和源表中的记录在表之前是否匹配。已加入
例如:—"在哪里"
1 | SELECT * FROM employee WHERE employee_id=101 |
。
例如:—"开"
有两个表Employee和Employee_Details,匹配的列是Employee_ID。
1 2 3 | SELECT * FROM employee INNER JOIN employee_details ON employee.employee_id = employee_details.employee_id |
希望我已经回答了你的问题。回复任何澄清。
I think this distinction can best be explained by the logical order of operations in SQL,which is,admissed:
- 包括连接在内的
WHERE - 法国电力公司
- 聚集
- 法国电力公司
- 法国电力公司
- 法国电力公司
- 法国电力公司
UNION INTERSECT EXCEPT - 法国电力公司
- 法国电力公司
- 法国电力公司
Joins不是选择声明的条款,而是
我在这张博客上解释了更多的事例。When running this query:
1 2 3 4 5 6 | SELECT a.actor_id, a.first_name, a.last_name, COUNT(fa.film_id) FROM actor a LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id WHERE film_id < 10 GROUP BY a.actor_id, a.first_name, a.last_name ORDER BY COUNT(fa.film_id) ASC; |
即使演员不在电影里演出,演员也会被过滤,就像他们的
1 2 3 4 5 6 7 | ACTOR_ID FIRST_NAME LAST_NAME COUNT -------------------------------------- 194 MERYL ALLEN 1 198 MARY KEITEL 1 30 SANDRA PECK 1 85 MINNIE ZELLWEGER 1 123 JULIANNE DENCH 1 |
I.E.just as if we inner joined the two tables.如果我们在
1 2 3 4 5 6 | SELECT a.actor_id, a.first_name, a.last_name, COUNT(fa.film_id) FROM actor a LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id AND film_id < 10 GROUP BY a.actor_id, a.first_name, a.last_name ORDER BY COUNT(fa.film_id) ASC; |
意思是,结果将包括演员,没有任何电影,或没有任何电影与EDOCX1〕〔28〕
1 2 3 4 5 6 7 8 9 10 11 | ACTOR_ID FIRST_NAME LAST_NAME COUNT ----------------------------------------- 3 ED CHASE 0 4 JENNIFER DAVIS 0 5 JOHNNY LOLLOBRIGIDA 0 6 BETTE NICHOLSON 0 ... 1 PENELOPE GUINESS 1 200 THORA TEMPLE 1 2 NICK WAHLBERG 1 198 MARY KEITEL 1 |
短期内
总是把你的假设放在最有意义的地方,逻辑上。
让我们考虑一下这些表:
一
1 | id | SomeData |
乙
1 | id | id_A | SomeOtherData |
号
编写此查询:
1 2 3 4 | SELECT * FROM A LEFT JOIN B ON A.id = B.id_A; |
将提供此结果:
1 2 3 4 5 6 7 8 9 10 11 12 | / : part OF the RESULT B +---------------------------------+ A | | +---------------------+-------+ | |/////////////////////|///////| | |/////////////////////|///////| | |/////////////////////|///////| | |/////////////////////|///////| | |/////////////////////+-------+-------------------------+ |/////////////////////////////| +-----------------------------+ |
。
A中是什么而不是B中是什么意味着B有空值。
现在,让我们考虑一下
1 2 3 4 5 6 7 8 9 10 11 12 13 | / : part OF the RESULT * : part OF the RESULT WITH the specific B.id_A B +---------------------------------+ A | | +---------------------+-------+ | |/////////////////////|///////| | |/////////////////////|///////| | |/////////////////////+---+///| | |/////////////////////|***|///| | |/////////////////////+---+---+-------------------------+ |/////////////////////////////| +-----------------------------+ |
编写此查询:
1 2 3 4 5 | SELECT * FROM A LEFT JOIN B ON A.id = B.id_A AND B.id_A = SpecificPart; |
。
将提供此结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 | / : part OF the RESULT * : part OF the RESULT WITH the specific B.id_A B +---------------------------------+ A | | +---------------------+-------+ | |/////////////////////| | | |/////////////////////| | | |/////////////////////+---+ | | |/////////////////////|***| | | |/////////////////////+---+---+-------------------------+ |/////////////////////////////| +-----------------------------+ |
。
因为这样会消除内部联接中不在
现在,让我们将查询更改为:
1 2 3 4 5 | SELECT * FROM A LEFT JOIN B ON A.id = B.id_A WHERE B.id_A = SpecificPart; |
结果是:
1 2 3 4 5 6 7 8 9 10 11 12 13 | / : part OF the RESULT * : part OF the RESULT WITH the specific B.id_A B +---------------------------------+ A | | +---------------------+-------+ | | | | | | | | | | +---+ | | | |***| | | | +---+---+-------------------------+ | | +-----------------------------+ |
。
因为整个结果都是针对
这是我的解决方案。
1 2 3 4 | 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 |
你必须要有
希望能帮上忙。