2012-02-26 85 views
4

是什么下面的SQL代码段之间的区别:On或Where在LEFT JOIN中有什么区别?

select count(*) 
from A 
left join B 
on a.id = b.id 
where a.status = 2 and 
b.id is NULL 

select count(*) 
from A 
left join B 
on a.id = b.id 
and a.status =2 
where b.id is NULL 

?我这样说的:Semantic difference between join queries,但我还是不知道哪一个是更好地使用

我已经花了过去一小时附加值读这篇文章,抓住这一切的答案,但我与“从来没有遇到过一起理解的代码示例这是最好的

回答

5

重写2个查询没有LEFT JOIN/IS NULL所以很明显,他们可以在某些情况下返回不同的数据集:

---Query 1 

SELECT COUNT(*) 
FROM a 
WHERE a.status = 2 
    AND NOT EXISTS 
     (SELECT * 
     FROM b 
     WHERE a.id = b.id 
    ) 

---Query 2 

SELECT COUNT(*) 
FROM a 
WHERE NOT (a.status = 2 
     AND EXISTS 
      (SELECT * 
       FROM b 
       WHERE a.id = b.id 
      ) 
     ) 

--- or: 

---Query 2 
SELECT COUNT(*) 
FROM a 
WHERE a.status <> 2 
    OR NOT EXISTS 
     (SELECT * 
     FROM b 
     WHERE a.id = b.id 
    ) 
+0

我明白了,所以查询1更好。我正确地假设,如果它是“B.status = 2”,那么它将在你的query2的例子1中存在()子句,所以(SELECT * from b WHERE a.id a = b.id AND b。状态= 2)? – edelwater 2012-02-27 00:08:32

+1

查询1和2不同,它们返回不同的结果。查询1不是更好,但更常见。在实际情况下,我从来没有遇到过Query2类型。 – 2012-02-27 00:10:19

+0

是的,对于第二个问题,一个'b.status = 2'条件会显着改变事物。这是非常普遍的情况(并且让它与左连接一起工作,您将该条件放在“ON”部分中)。 – 2012-02-27 00:12:05

10

关键是如何使用LEFT连接,一个会过滤结果,另一个只会失败LEFT连接,从JOIN的左侧保留数据。

(1)左加入上a.id = b.id 其中a.status = 2

忽略其它过滤器B,这表示以LEFT JOIN对表B,因此,“尝试使用条件a.id=b.id加入表B“。
如果不能进行匹配,请将记录保留在左表(即A)上。继的是,在剩余的记录,过滤掉(即删除)不匹配记录a.status=2

(2)左先连接B a.id = b.id 和a.status = 2

忽略其他过滤器,这表示在2种情况下对表B进行左加入,因此,“试图在条件a.id = b.id and a.status =2上加入表B”。如果在两种条件下都没有得到B的记录(即使与B无关),无论如何都要保留记录。

5

不同之处在于条件是逻辑评估的地方,反过来又会影响结果集。

在你的例子(重新格式化),您有:

实施例1

SELECT COUNT(*) 
    FROM A LEFT JOIN B ON a.id = b.id 
WHERE a.status = 2 AND b.id is NULL 

实施例2

SELECT COUNT(*) 
    FROM A LEFT JOIN B ON a.id = b.id AND a.status = 2 
WHERE b.id is NULL 

在第一种情况中,LEFT JOIN被施加并生成结果集;然后使用WHERE子句中的两个条件对其进行过滤。

在第二种情况下,LEFT JOIN由a.status上的筛选条件构成,并且在某些情况下可能会从LEFT JOIN更改结果集。然后使用主WHERE子句过滤此结果集。

实施例2基本上等同于:

实施例2A

SELECT COUNT(*) 
    FROM (SELECT * FROM A WHERE a.status = 2) AS A 
    LEFT JOIN B ON a.id = b.id 
WHERE b.id is NULL 

对于某些查询(但可能不是这样的一个),差异可以无关紧要。


让我们尝试创建一些简单的示例数据:

Table A    Table B 
id status   id 
4  2    1 
5  3 

实施例1将具有中间结果集:

a.id a.status b.id 
4  2   null 
5  3   null 

和WHERE子句消除的第二行。

实施例2将具有中间结果集:

a.id a.status b.id 
4  2   null 

在本例中,最终结果是一样的,并且我还没有能够拿出数据不结束的相同。

如果四处移动的查询条件位于外连接表上并且比简单的相等性更复杂,则可以看到效果。

+1

我认为例2只有在它是内连接时才相当。 – dotjoe 2012-02-26 23:32:17

+1

您的评论中的'that'含糊不清 - 假设您将FROM(SELECT * FROM A WHERE a.status = 2)AS A'指定为'that'(我们称之为例2A),然后我挑战你拿出一个样本数据集,其中例2和例2A有区别。 – 2012-02-26 23:47:45

+0

@jonathan:对于您的数据集,示例2将具有包含2行的中间(和最终)结果集,而不是1.而示例2A将具有1行的结果集。 – 2012-02-26 23:58:19

1

也许这是更容易跟踪:

SELECT id 
    FROM A 
WHERE status = 2 
EXCEPT 
SELECT id 
    FROM B; 

万一你只是感兴趣结果的基数:

SELECT COUNT(*) 
    FROM (SELECT id 
      FROM A 
      WHERE status = 2 
     EXCEPT 
     SELECT id 
      FROM B) AS DT1; 
相关问题