LEFT JOIN中On或Where之间的区别是什么?

时间:2012-02-26 23:19:16

标签: sql left-join

以下SQL代码之间有什么区别:

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但我仍然不知道哪个更好用

  

我花了过去一小时阅读本文并把握所有答案的附加价值,但我理解代码示例和“从未遇到过这样”最好的

4 个答案:

答案 0 :(得分:10)

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

(1)在a.id = b.id上左连接B. 其中a.status = 2

忽略其他过滤器,这表示对表B进行LEFT JOIN,因此,“尝试使用条件a.id=b.id”加入表B.“ 如果你不能匹配,请将记录保存在左表(即A)。在此之后,在剩余记录上,FILTER out(即REMOVE)记录与a.status=2不匹配

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

忽略其他过滤器,这表示在两个条件下对表B进行LEFT JOIN,因此,“尝试在两个条件a.id = b.id and a.status =2”上加入表B.如果两个条件都没有得到B的记录(即使一个与B无关),请保留A的记录。

答案 1 :(得分: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

在这个例子中,最终结果是一样的,而且我还没有能够提出不一样的数据。

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

答案 2 :(得分:5)

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

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

答案 3 :(得分: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;