当表左连接时where子句和on子句之间的区别是什么?

时间:2011-11-29 12:58:08

标签: sql where-clause

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以同样的方式运行它们吗?感谢。

6 个答案:

答案 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)

无论如何,它确实取决于查询优化器。

看看下面的内容:

Is a JOIN faster than a WHERE?

答案 2 :(得分:4)

在考虑SQL语法时,了解the logical order of SQL operations很重要。 JOINON子句中的运算符(并且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 Ba​​nnister指出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会返回相同的结果,所以请检查优化器。