简体   繁体   English

在SQL Server 2005中的比较测试中处理空值

[英]Dealing with Nulls in Comparison Tests in SQL Server 2005

I was writing a Stored procedure today, and I ran into a problem where if one of the values is null (whether it be from a SELECT statement or whether it be a passed in parameter) my expression would evaluate to false where it ought to evaluate to true. 我今天正在编写一个存储过程,但遇到一个问题,如果其中一个值为空(无论是来自SELECT语句还是传入的参数),我的表达式在应该计算的地方将评估为false真实。

SET ANSI_NULLS ON;
DECLARE @1 INT;
DECLARE @2 INT;
DECLARE @3 INT;
DECLARE @4 INT;

SET @1 = 1;
SET @2 = NULL;
SET @3 = 3;
SET @4 = 3;

IF ((@1 <> @2) OR (@3 <> @4))
   BEGIN
     SELECT 1;
   END
ELSE
   BEGIN
     SELECT 2;
   END
SELECT @1, @2, @3, @4

Returns: 返回值:

2

1, NULL, 3, 3

I expected it to return: 我希望它能返回:

1

1, NULL, 3, 3

I know I'm missing something simple, anybody have any idea what it is? 我知道我缺少简单的东西,有人知道它是什么吗?

Related Question 相关问题

SQL: Why are NULL Values filtered Out within this WHERE clause? SQL:为什么在此WHERE子句中过滤掉NULL值?

One way of dealing with this is you can wrap your NULL values in a known unexpected value, ie -1 : 解决此问题的一种方法是,您可以将NULL值包装在已知的意外值中,即-1

IF ((ISNULL(@1, -1) <> ISNULL(@2, -1)) OR (ISNULL(@3, -1) <> ISNULL(@4, -1)))
   BEGIN
     SELECT 1;
   END
ELSE
   BEGIN
     SELECT 2;
   END

Obviously if -1 was a possibility then use a different number. 显然,如果可能为-1 ,则使用其他数字。 If there is no non-possible value, then you will have to use CASE statements. 如果没有不可能的值,那么您将不得不使用CASE语句。

A concise way of assigning NULL values to a 'safe' value follows: 为“安全”值分配NULL值的简洁方法如下:

SET @1 = ISNULL(@1, -1)

This allows the contional test code to remain 'clutter-free'. 这样可以使常规测试代码保持“整洁”。

Any comparison that involves a NULL will evaluate to NULL instead of True or False. 任何涉及NULL的比较都将评估为NULL,而不是True或False。 Hence the ELSE block of your code gets executed. 因此,将执行代码的ELSE块。 Because although Null is not the same as False, it definitely isn't the same as True. 因为尽管Null与False不同,但它肯定与True不同。

Yes, nulls are a pain. 是的,空值是一种痛苦。 A few ways to handle them. 处理它们的几种方法。 Some of these are MS-SQL specific functions: 其中一些是MS-SQL特定的功能:

Method 1: Be real explicit about all the options 方法1:真正明确所有选项

IF ((@1 <> @2) 
OR (@1 is NULL AND @1 IS NOT NULL)
OR (@1 is NOT NULL AND @1 IS NULL)
OR (@3 <> @4)
OR (@3 is NULL AND @4 IS NOT NULL)
OR (@3 is NOT NULL AND @4 IS NULL))

Method 2: Us a function to change the null into something else, that you know won't match: 方法2:我们提供了一个将null更改为其他不匹配的函数:

IF ((IsNull(@1,-1) <> IsNull(@2,-1) 
OR (IsNull(@3,-1) <> IsNull(@4,-1))

Sometimes this first option is better because it is more explicit. 有时,第一个选项会更好,因为它更明确。 The second one has the side-effect of matching a NULL to a NULL. 第二个副作用是将NULL匹配为NULL。

Edit: if you want to set them ahead of time, just do 编辑:如果您想提前设置它们,那就去做吧

SET @1 = IsNull(@1,-1);

If it is null, it will set it to -1. 如果为null,则将其设置为-1。 If not, it will leave it alone. 如果没有,它将不理会它。 I think its cleaner to do it INSIDE the function, per my Method 2. 我认为按照我的方法2,它可以在函数内部更干净。

Here's a way to do it without functions, and also might be easier to read. 这是在没有函数的情况下进行操作的一种方法,而且可能更易于阅读。 (My eyes start to cross when I see a bunch of NULL-testing functions close together.) (当我看到一堆NULL测试功能并拢时,我的视线开始交叉。)

IF (@1 IS NULL AND @2 IS NULL) OR (@1 = @2)
BEGIN
    IF (@3 IS NULL AND @4 IS NULL) OR (@3 = @4) 
    BEGIN
        SELECT 2
    END
    ELSE
    BEGIN
        SELECT 1
    END
END
ELSE
BEGIN
    SELECT 1
END

If you want to be even more confused, try running the opposite test, as follows: 如果您想更加困惑,请尝试运行相反的测试,如下所示:

SET ANSI_NULLS ON;
DECLARE @1 INT;
DECLARE @2 INT;
DECLARE @3 INT;
DECLARE @4 INT;
SET @1 = 1;
SET @2 = NULL;
SET @3 = 3;
SET @4 = 3;
IF ((@1 = @2) AND (@3 = @4))
   BEGIN     SELECT 1;
   ENDELSE   
   BEGIN     SELECT 2;   
   END
SELECT @1, @2, @3, @4

The result will not be what you expect from your previous experiment. 结果将与您之前的实验不同。

The reason is that SQL engages in a complicated three value logic when it's evaluating expressions that might contain NULLs. 原因是SQL在评估可能包含NULL的表达式时会使用复杂的三值逻辑。

NULL = 3 is not TRUE. NULL = 3不是TRUE。 It's not FALSE either. 这也不是错误的。 It's NULL. 这是NULL。 NULL = NULL is not TRUE. NULL = NULL不是TRUE。 It's not FALSE either. 这也不是错误的。 It's NULL. 这是NULL。

It's easy to get all mixed up with this. 很容易混淆所有这些。 The best way to avoid confusion is to constrain all your critical data to be NOT NULL. 避免混淆的最好方法是将所有关键数据限制为NOT NULL。 However, the requirments may prevent you from doing this, in which case you are just going to have to figure out 3 valued logic, SQL style. 但是,这些要求可能会阻止您执行此操作,在这种情况下,您只需要弄清楚3种有价值的逻辑,即SQL风格。

Don't ask me to defend this. 不要问我为这个辩护。

(In some environments, UNKNOWN is used in place of NULL for results that are not TRUE or FALSE.) (在某些环境中,对于非TRUE或FALSE的结果,使用UNKNOWN代替NULL。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM