Where Clause 'drops' 行数比预期多

Where Clause 'drops' more rows than expected

我有一个 SQL Server 2008 R2 查询返回 "hypothetically" 100 行。我实际上正在处理 7k - 8k 行。

Where 子句是这样的:

Where Col_a = 'Y'
  And Col_b = 'N'
  And Col_c = 'X'

并且其中 25 行在 Col_d 中有 'P'。

我补充了:

And Col_d = 'P'

并且查询返回了预期的 25 行。

然后我改成了

And Col_d <> 'P'

我希望得到 75 行,但我只得到了 50 行。

我认为添加“And Col_d <> 'P'”只会限制 Col_d 中有 'P' 的行。

为什么不是这样,当我说 And Col_d <> 'P'?

时,我如何弄清楚还有什么东西被丢弃了

正如我所说的 - 我实际上正在处理更大的数字,所以要用眼睛观察它并不容易。

如有任何帮助,我将不胜感激。

谢谢!

如评论中所述,null 在比较方面是 special case

假设以下数据。

id     someVal
----
0      null
1      1
2      2

有查询:

select id
from table
where someVal = 1

会return id 1

select id
from table
where someVal <> 1

会return id 2

select id
from table
where someVal is null

会return id 0

select id
from table
where someVal is not null

return 两个 ID 12

如果您希望空值 "counted" 作为 = <> 比较中的值,则需要将其强制转换为:

select id
from table
where isNull(someVal, -1) <> 1

returns 02

或者您可以更改 ANSI Null 设置。

What I want to do is only exclude the rows that have 'P' in Col_d

所以在您的特定情况下,因为您希望将 Col_D 中的 null 视为非 P 行,您的查询可能如下所示:

select * 
from someTable
Where Col_a = 'Y'
  And Col_b = 'N'
  And Col_c = 'X'
  And isNull(Col_D, 'someArbitraryValue') <> 'P'

您必须执行上述操作,因为正如我在整个答案和链接中指出的那样 null 与值的比较方式不同。您需要使 null 不为空(通过 isNull(Col_D, 'someArbitraryValue') 完成)或更改 ANSI NULL 设置以便将其比较为等于或不等于某个值。

或者正如@Andrew 指出的那样 magic numbers 是不好的(someArbitraryValue),所以你可以改为:

select * 
from someTable
Where Col_a = 'Y'
  And Col_b = 'N'
  And Col_c = 'X'
  And (Col_D <> 'P' OR Col_D is null)

通常我会直接执行上面的查询,我用另一种方式来做,主要是为了指出 null 比较与值之间的差异。