2016-09-26 141 views
1

我继承了一些老的存储过程的今天,跨遵循这个一般模式的几个例子来,其中@Test一些INT值:是否有必要测试NULL是否也测试大于?

IF @Test IS NOT NULL AND @Test > 0 
    -- do something... 

我的理解是,如果@TestNULL,那么它就没有价值,并且不大于,小于或甚至等于零。因此,对于测试是NULL在上面的代码冗余:

IF @Test > 0 
    -- do something... 

这第二个版本似乎工作得很好,而且是更具可读性IHMO。

所以,我的问题是:我认为NULL在这个例子中是不必要的,或者是否有一些明显的用例,我在这里忽略它可能会出现可怕的错误?

注:在某些情况下,很明显的意图是检查值的存在,我已经改变了那些IF EXISTS ...我的问题是更关心的是上文所述的一般情况。

+0

测试不是多余的。如果Test为空,那么IF测试的结果> 0会怎样? – GuidoG

+2

'IF @test> 0'就足够了,除非你没有其他的行为,如果@test为null – Fabio

+0

我建议试试像'select case when null> 5或null <= 5 then 1 else 0 end '并且如果你用NOT取代整个条件会发生什么 - SQL有'true/false'的3个状态,然后是null - 在我看来,你不希望将NULL送入它,除非你准备永远非常在意如何处理NULL – Cato

回答

2

与NULL比较是必要的,如果你使用else语句

例如:

declare @t int 
set @t=null 
if (@t>0) print '1' -- works fine 
if (@t<0) print '2' --works fine 

if (@t>0) 
    print '3' --works fine 
else print '4' --here we start getting problems, because we are sure that @t<=0 that is obviously not true 
+0

是的,这是一个很好的观点。碰巧,到目前为止,我所看到的代码都没有遵循特定的形式,但它绝对是一个需要注意的用例。 –

+0

我接受了这个答案,因为它通过提供一个合理的方案直接解决了这个问题,其中*不检查NULL可能会导致意想不到的结果。感谢大家的贡献,提出了很多有用的观点。 –

5

在SQL中,所有与NULL值比较的结果均为false。 所以你总是必须明确地检查NULL,如果你想对它采取行动。 因此,在这种情况下,额外的测试是没有必要的。

+2

实际上它们不会被评估为false,而是被归为false的null,但这不会改变事实,您必须检查它。 – Pred

+0

是的,抱歉,轻微的错误措辞。比较的结果是NULL,它不是布尔值TRUE。 –

+0

@Pred为什么在这个例子中说“你必须检查它”? –

1

你可以用

if isnull(@test, 0) > 0 

这种方式取代它,它会更短,但您仍已经检查了一切

+0

好妥协,谢谢! –

4

@FlorianHeer是对的。 NULL> 0将最终评估为false,但是@Pred指出这是因为Null> 0实际上评估为null,而null强制转换为一个比特为假......

null是未知的,因此与这也是未知的。考虑算术函数,如加法1 + NULL = NULL或连接'A' + NULLL = NULL。 NULL意味着SQL数据库引擎无法解释它的值是什么,所以任何函数或比较都是未知的。

@MikkaRin指出,它是在case语句或IF语句的ELSE部分中的假设,可能会出现问题,但我们也可以在连接的上下文中思考这个问题,以及您可能希望如何看结果。

DECLARE @Table1 AS TABLE (Col INT) 
DECLARE @Table2 AS TABLE (Col INT) 
INSERT INTO @Table1 VALUES (1),(2),(3) 
INSERT INTO @Table2 VALUES (1),(NULL),(3),(4) 

SELECT * 
FROM 
    @Table1 t1 
    INNER JOIN @Table2 t2 
    ON t1.Col <> t2.Col 

当然,您可能会认为,因为NULL不等于1,2,3应该包含在结果集中。但是null是未知的,所以SQL说的很好,我不知道NULL是否可以是1,2,3,所以我不能返回结果。

现在让我们做同样的事情,但在第一个表添加一个NULL:

DECLARE @Table1 AS TABLE (Col INT) 
DECLARE @Table2 AS TABLE (Col INT) 
INSERT INTO @Table1 VALUES (1),(2),(3),(NULL) 
INSERT INTO @Table2 VALUES (1),(NULL),(3),(4) 

SELECT * 
FROM 
    @Table1 t1 
    INNER JOIN @Table2 t2 
    ON t1.Col = t2.Col 

同样的,你可能会认为NULL是=为NULL,但空的任何比较被认为是不明所以,即使两个表具有在它的NULL它不会在数据集中返回。

现在考虑:

DECLARE @Table1 AS TABLE (Col INT) 
INSERT INTO @Table1 VALUES (1),(2),(3),(NULL) 

SELECT *, CASE WHEN Col < 2 THEN Col ELSE 1000 END as ColCase 
FROM 
    @Table1 t1 

这将使得即便是NULL 1000问题是应该NULL未知的是1000?如果NULL是未知的,我们怎么知道它不小于2?

对于您的大量操作,可能只需比较@Value > 1即可,但特别是当您在IF语句的情况下开始处理ELSE或加入对立时,应考虑处理NULL。如@GuidoG使用ISNULL()COALESCE()指出。

恕我直言明确表示您在操作期间的意图,以适当考虑空值,权衡最小的打字节省。

+0

感谢详细的例子马特,非常有用。我想我的价值(至少在原始问题的相对简单的用例中)是清晰的。通常,这是通过按照你说的那样明确来实现的,但是我正在使用的代码充斥着NULL检查,可以说它在一定程度上掩盖了其更大的目的。唯一可以处理的情况似乎是积极的整数,所以我怀疑我不需要对NULL检查过于保守。在这种情况下,你会发现哪两个例子更清晰? –

+1

我会发现“IF ISNULL(@ Test,0)> 0”是最简洁和最清晰的。它是您精益代码之间的混合体,并使您有意如何处理清零。 – Matt

+0

是的,我认为语法开始吸引我... –