我今天正在编写一个存储过程,遇到一个问题,如果其中一个值为null(无论是来自SELECT
语句还是传入参数)我的表达式会评估如果它应该评估为真,那就是假。
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
返回:
2
1, NULL, 3, 3
我期待它回归:
1
1, NULL, 3, 3
我知道我错过了一些简单的东西,任何人都知道它是什么?
SQL: Why are
NULL
Values filtered Out within thisWHERE
clause?
答案 0 :(得分:5)
解决此问题的一种方法是,您可以将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
显然,如果-1
是可能的,那么使用不同的数字。如果没有不可能的值,那么您将不得不使用CASE
语句。
将NULL
值分配给'安全'值的简明方法如下:
SET @1 = ISNULL(@1, -1)
这允许contional测试代码保持“无杂乱”。
答案 1 :(得分:4)
任何涉及NULL的比较都将计算为NULL而不是True或False。因此,代码的ELSE块被执行。因为尽管Null与False不同,但它肯定与True不同。
答案 2 :(得分:2)
是的,空是一种痛苦。处理它们的几种方法。其中一些是MS-SQL特定的功能:
方法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))
方法2:使用一个函数将null更改为其他您知道不匹配的函数:
IF ((IsNull(@1,-1) <> IsNull(@2,-1)
OR (IsNull(@3,-1) <> IsNull(@4,-1))
有时这第一个选项更好,因为它更明确。 第二个具有将NULL与NULL匹配的副作用。
编辑:如果您想提前设置它们,请执行
SET @1 = IsNull(@1,-1);
如果为null,则将其设置为-1。如果没有,它将不管它。根据我的方法2,我认为它更清晰,可以在功能中进行。
答案 3 :(得分:2)
这是一种没有功能的方法,也可能更容易阅读。 (当我看到一堆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
答案 4 :(得分:1)
如果您想更加困惑,请尝试运行相反的测试,如下所示:
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
结果将不是您对之前实验的期望。
原因是SQL在评估时会参与复杂的三值逻辑 可能包含NULL的表达式。
NULL = 3不为TRUE。这也不算假。它是NULL。 NULL = NULL不为TRUE。这也不算假。它是NULL。
很容易让这一切搞砸了。避免混淆的最佳方法是将所有关键数据约束为NOT NULL。但是,这些要求可能会阻止你这样做,在这种情况下,你只需要弄清楚3种有价值的逻辑,即SQL风格。
不要让我为此辩护。
(在某些环境中,对于非TRUE或FALSE的结果,使用UNKNOWN代替NULL。)