如果还测试大于?是否有必要测试NULL?

Mic*_*lin 1 t-sql sql-server

我今天继承了一些旧的存储过程,并且遇到了几个遵循这种一般模式的例子,其中@Test有一些INT值:

IF @Test IS NOT NULL AND @Test > 0
    -- do something...
Run Code Online (Sandbox Code Playgroud)

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

IF @Test > 0
    -- do something...
Run Code Online (Sandbox Code Playgroud)

第二个版本似乎工作正常,IHMO更具可读性.

所以,我的问题是:我对NULL这种情况下不必要的理解是否正确,或者是否有一些明显的用例我在这里忽略了它可能会出现可怕的错误?

注意:在某些情况下,显然意图是检查是否存在值,并且我已经将这些更改为IF EXISTS......我的问题更关注上面概述的一般情况.

小智 5

在SQL中,所有与NULL值的比较都计算为false.因此,如果您希望对其执行操作,则必须明确检查NULL.因此,在这种情况下,不需要额外的测试.

  • 实际上他们不会评估为false,而是将其归结为false,但这不会改变事实,你必须检查它. (2认同)

Mat*_*att 5

@FlorianHeer 说得对。NULL > 0 最终将计算为 false,但正如 @Pred 指出的那样,这是因为 Null > 0 实际上计算为 null,而 null 转换为 bit 是 false...

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
Run Code Online (Sandbox Code Playgroud)

自然地,您可能会认为因为 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
Run Code Online (Sandbox Code Playgroud)

您可能再次认为 NULL = 到 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
Run Code Online (Sandbox Code Playgroud)

这甚至会使得 NULL 1000 问题是 NULL 未知数应该是 1000 吗?如果 NULL 未知,我们如何知道它不小于 2?

对于许多操作来说,比较可能就足够了@Value > 1,但特别是当您开始处理 IF 语句中的 ELSE 或加入对立时,您应该考虑处理 NULL。例如使用ISNULL()orCOALESCE()正如@GuidoG 指出的那样。

恕我直言,在操作过程中明确您的意图以适当地考虑空值会权衡键入的最小节省。


Mik*_*Rin 3

如果使用 ELSE 语句,则需要与 NULL 进行比较:

例如:

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
Run Code Online (Sandbox Code Playgroud)