SQL1:
select t1.f1,t2.f2
from t1
left join t2 on t1.f1 = t2.f2 and t1.f2=1 and t1.f3=0
SQL2:
select t1.f1,t2.f2
from t1
left join t2 on t1.f1 = t2.f2
where t1.f2=1 and t1.f3=0
区别在于where和on子句,是否有相同的返回结果?有什么区别? DBMS以同样的方式运行它们吗?感谢。
答案 0 :(得分:24)
where
子句适用于整个结果集; on clause
仅适用于相关联接。
在提供的示例中,所有附加条件都与联接内侧的字段相关 - 因此在此示例中,两个查询实际上是完全相同的。
但是,如果您在联接的外部一侧的表格中包含了一个条件,则会产生显着差异。
您可以从以下链接获取更多信息:http://ask.sqlservercentral.com/questions/80067/sql-data-filter-condition-in-join-vs-where-clause
例如:
select t1.f1,t2.f2 from t1 left join t2 on t1.f1 = t2.f2 and t2.f4=1
select t1.f1,t2.f2 from t1 left join t2 on t1.f1 = t2.f2 where t2.f4=1
- 做不同的事情 - 前者将连接到t2记录,其中f4为1,而后者实际上已转回内部连接到t2。
答案 1 :(得分:7)
第一个查询比第二个查询更快,因为连接条件比第二个查询更具体:返回使用where子句过滤的记录是没有意义的(最好不要将它们返回到all-query1)
无论如何,它确实取决于查询优化器。
看看下面的内容:
答案 2 :(得分:4)
在考虑SQL语法时,了解the logical order of SQL operations很重要。 JOIN
是ON
子句中的运算符(并且JOIN
属于相关的FROM
)。 FROM
子句是逻辑执行的第一个操作(优化程序仍然可以选择对事物进行重新排序)。
在您的示例中,并没有什么区别,但是很容易构造一个as I've shown in this blog post about the difference between ON
and WHERE
in OUTER JOIN
(博客文章中的示例使用Sakila database):
第一个查询
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 fa.film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;
收益:
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
因为我们在WHERE
子句中过滤了外部联接表,所以LEFT JOIN
实际上变成了INNER JOIN
。为什么?因为如果我们有一个不在电影中放映的演员,那么该演员的唯一一行将有fa.film_id IS NULL
,因此fa.film_id < 10
谓词将产生NULL
。就像INNER JOIN
一样,此类参与者也被排除在结果之外。
第二个查询
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 fa.film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;
收益:
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
现在,结果中包括没有电影的演员,因为fa.film_id < 10
谓词是LEFT JOIN
的{{1}}谓词的一部分
结论
始终将谓词放在逻辑上最有意义的地方。
ON
操作的一部分?将它们放在JOIN
ON
产品进行过滤?将它们放在JOIN
答案 3 :(得分:2)
1)
SQL1: select t1.f1,t2.f2 from t1 left join t2 on t1.f1 = t2.f2 **and** t1.f2=1 and t1.f3=0
在此,解析器将使用这3个条件检查t1的每一行与t2的每一行。获得更快的结果。
2)SQL2: select t1.f1,t2.f2 from t1 left join t2 on t1.f1 = t2.f2 **where** t1.f2=1 and t1.f3=0
在这里,join只接受第一个条件,然后从这两个条件过滤从join获得的结果。并且比第一次查询需要更多时间。
您可以从以下链接获取更多信息:http://ask.sqlservercentral.com/questions/80067/sql-data-filter-condition-in-join-vs-where-clause
答案 4 :(得分:2)
关系代数允许WHERE子句和INNER JOIN中谓词的可互换性,因此即使带有WHERE子句的INNER JOIN查询也可以让优化器重新排列谓词,以便在JOIN过程中可以排除它们。
我建议您以尽可能最简单的方式编写查询。
有时这包括使INNER JOIN相对“不完整”,并在WHERE中放入一些标准,以简化过滤标准列表。
您可以从此链接获得更多信息: http://ask.sqlservercentral.com/questions/80067/sql-data-filter-condition-in-join-vs-where-clause
例如,而不是:
SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
ON ca.CustomerID = c.CustomerID
AND c.State = 'NY'
INNER JOIN Accounts a
ON ca.AccountID = a.AccountID
AND a.Status = 1
写:
SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
AND a.Status = 1
但这当然取决于。
答案 5 :(得分:2)
这两个查询 NOT 相同。
Mark Bannister指出where
子句适用于整个结果集,但clause
适用于联接。
在您的情况下,对于SQL 1,LEFT JOIN条件在右侧过滤连接,但在任何WHERE过滤之前始终返回左侧。由于没有WHERE条件,因此总是返回所有t1。
在SQL 2中,LEFT JOIN条件过滤了右侧显示的一些结果,但同样返回了所有t1。但是这次WHERE条件可能会过滤掉一些t1的记录。
INSERT INTO `t1` (`f1`,`f2`,`f3`) VALUES (1,1,1);
INSERT INTO `t2` (`f3`) VALUES (1);
由于它们指向不同的逻辑,因此必须根据该查询编写查询,它为我们提供了强大的功能和灵活性。
INNER JOIN会返回相同的结果,所以请检查优化器。