SQL Server - 隐式连接与显式不同的结果

时间:2016-02-04 20:29:42

标签: sql sql-server

我的印象是

SELECT *
FROM TableA a
LEFT JOIN TableB b ON a.ID = b.AID AND b.SomeString <> 'ABC'

SELECT *
FROM Table a
LEFT JOIN TableB b ON a.ID = b.AID
WHERE b.AID IS NULL OR b.SomeString <> 'ABC'

会产生相同的结果。

不幸的是,在我的情况下,他们不是:-(

他们可能没有任何理由?

2 个答案:

答案 0 :(得分:4)

表A

+----+
| ID |
+----+
|  1 |
|  2 |
|  3 |
+----+

表B

+-----+-----------------+
| AID |   SomeString    |
+-----+-----------------+
|   1 | SomeOtherString |
|   2 | ABC             |
+-----+-----------------+

查询1

SELECT *
FROM   TableA a
       LEFT JOIN TableB b
         ON a.ID = b.AID
            AND b.SomeString <> 'ABC'

这会将A的每一行与B匹配a.ID = b.AID AND b.SomeString <> 'ABC'的每一行联接起来。如果与A中的行匹配的行数为零,那么对于表NULL中的列,B的结果将保留(如下面的Id = 2所示 - 与id匹配的单行&#39 ; t满足第二个条件,Id = 3,其中甚至没有与id匹配的行

+----+------+-----------------+
| ID | AID  |   SomeString    |
+----+------+-----------------+
|  1 | 1    | SomeOtherString |
|  2 | NULL | NULL            |
|  3 | NULL | NULL            |
+----+------+-----------------+

查询1.5

SELECT *
FROM TableA a
LEFT JOIN TableB b ON a.ID = b.AID

这稍微改变了语义,因为现在被认为是匹配只需要满足id谓词而不是字符串条件。带有ids 2和3的A中的行与此新匹配条件下的B中的行匹配,并且只有id = 3被外部联接添加回来。

+----+------+-----------------+
| ID | AID  |   SomeString    |
+----+------+-----------------+
|  1 | 1    | SomeOtherString |
|  2 | 2    | ABC             |
|  3 | NULL | NULL            |
+----+------+-----------------+

查询2

SELECT *
FROM   TableA a
       LEFT JOIN TableB b
         ON a.ID = b.AID
WHERE  b.AID IS NULL
        OR b.SomeString <> 'ABC' 

这将在Query 1.5结果中显示的行上运行WHERE b.AID IS NULL OR b.SomeString <> 'ABC谓词。离开你两行。外连接保留的行是其中之一。

+----+------+-----------------+
| ID | AID  |   SomeString    |
+----+------+-----------------+
|  1 | 1    | SomeOtherString |
|  3 | NULL | NULL            |
+----+------+-----------------+

答案 1 :(得分:3)

由于NULL逻辑。

在第一个查询中,您获得A中的所有行,仅当键与匹配时才会在B上连接.S.SomeString不等于ABC。如果b.SomeString为null,那么如果找不到该键,则会得到…and NULL is not equal to ABC。根据NULL比较的规则,将NULL与任何“失败”进行比较,例如NULL <> ‘ABC’等同于假。最终结果:如果找不到ID,则b.SomeString为NULL,并从返回的集合中丢弃该行。

在第二个查询中,您将获得A中的所有行,仅当键匹配时才连接到B.并且只有 表之后才会评估where子句。它(基本上)表示保持 ID与不匹配的行.S.SomeString&lt;&gt; “ABC”(如上所述,将排除NULL)。因此,您最终得到ID不匹配的行,行匹配b.SomeSting不是ABC的行。

这些东西可能很难理解,难以解释,而且很难在没有样本数据的情况下解释 - 这就是我说你应该查看一些问题,直到你了解它是如何工作的。