Sql 左联接中的On或Where之间有什么区别?

Sql 左联接中的On或Where之间有什么区别?,sql,left-join,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 及 ??我读到这篇文章:但我仍然不知道哪一个更好用 在过去的一个小时里,我一直在阅读这篇文章,并掌握了所有答案的附加值,但我理解了代码示例,从未遇到过最好的例子 这是如何使用左连接的关键,一个将过滤结果,另一个只会使左连接失败,保留连接左侧的数据 1在a.id=B.id上左连接B 其中a

以下几段SQL代码之间的区别是什么:

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

??我读到这篇文章:但我仍然不知道哪一个更好用

在过去的一个小时里,我一直在阅读这篇文章,并掌握了所有答案的附加值,但我理解了代码示例,从未遇到过最好的例子


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

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

忽略其他筛选器,这表示对表B进行左连接,因此,请尝试使用条件a.id=B.id连接到表B。 如果无法匹配,请保留左表中的记录,即a。之后,在其余记录上,过滤掉,即删除与a不匹配的记录。状态=2

2左连接B 在a.id=b.id和a.status=2时


忽略其他筛选器,这表示在2个条件下对表B进行左联接,因此,尝试在两个条件a.id=B.id和a.status=2下联接到表B。如果在给定两个条件的情况下,即使其中一个条件与B无关,也没有从B获得任何记录,则无论如何都要保留A的记录。

不同之处在于逻辑计算条件的位置,这反过来会影响结果集

在重新格式化的示例中,您有:

例1

例2

在第一种情况下,应用左连接并生成结果集;然后使用WHERE子句中的两个条件对其进行过滤

在第二种情况下,使用a.status上的过滤条件形成左连接,并且在某些情况下可能会改变左连接的结果集。然后使用main WHERE子句过滤此结果集

示例2基本上等同于:

例2A

对于一些查询,但可能不是这个查询,差异可能很重要

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

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
a.id   a.status   b.id
4      2          null
WHERE子句消除了第二行

示例2将有一个中间结果集:

a.id   a.status   b.id
4      2          null
5      3          null
a.id   a.status   b.id
4      2          null
在这个例子中,最终的结果是相同的,我还没有找到结果不一样的数据


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

在不使用左联接/的情况下重写2个查询是空的,因此很明显,在某些情况下,它们可以返回不同的数据集:

---Query 1

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


也许这更容易理解:

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;

我认为,只有当它是一个内部连接时,示例2才会与之等效。您的注释中的“that”是不明确的-假设您指的是FROM SELECT*FROM A的变体,其中A.status=2作为“that”,我们称之为示例2A,然后,我要求您提供一个示例数据集,其中示例2和示例2A之间存在差异。@jonathan:对于您的数据集,示例2将有一个中间和最终结果集,其中包含2行,而不是1行。示例2A将有一个1行的结果集。我的理解是示例1相当于示例2A。我不知道如何将a.status=2从左连接条件移动到子查询中,并使其相等。示例2的中间结果不是有两行吗,而示例2A只有一行吗?如果您的示例2A与示例1有任何相同之处,我理解,那么查询1更好。假设它是B.status=2,那么它将出现在exist子句中查询2的示例1中,因此从B中选择*,其中a.id a=B.id和B.status=2?查询1和查询2不同,它们返回不同的结果。查询1不是更好,但更常见。我从未在实际情况中遇到过Query2类型。是的,对于你的第二个问题,b.status=2条件会使情况发生巨大变化。这是非常常见的情况,要使用左连接,您需要将该条件放在ON部分中。+1这是表示查询的一种明确方式。左侧连接中的null样式查询可能非常混乱!当该条件仅与主表相关时,情况更糟
---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
      )
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;