x = null 与 x IS NULL 之间的区别

Difference between x = null vs. x IS NULL

在 Snowflake 中,条件表达式中的 x = NULLx IS NULL 有什么区别?根据经验,当我想查找某些列为空白的行时, x IS NULL 就是我想要的。我问是因为 x = NULL 被视为有效语法,我很好奇这个表达式是否有不同的应用程序。

与大多数 SQL 语言一样,比较 NULL = NULL 不会 return TRUE。在 SnowFlake 中,它 returns NULL,与 NULL 值的任何比较也是如此。其原因与 SQL 的错综复杂的历史有关,并且一直在争论这是否是一个好功能。无论如何,这就是我们所拥有的。

因此,当您比较两个可能为 NULL 的值时,这里有一些您通常可以使用的不同解决方案。

-- NVL will return the second value if the first value is NULL
-- So if both of your values are NULL, then an NVL around each of them will 
-- return a value so that they are both equal.
-- This only works if you know that your values will never be equal to -1 for example
SELECT ...
WHERE NVL(x, -1) = NVL(y, -1)

-- A little messier, especially among more complicated filters,
-- but guaranteed to work regardless of values
SELECT ...
WHERE x = y OR (x is null and y is null)

-- My new favorite which works in SnowFlake (thanks to @waldente)
SELECT x IS NOT DISTINCT FROM y;

-- For most SQL languages, this is a neat way to take advantage of how 
-- INTERSECT compares values which does treat NULLs as equal
SELECT ...
WHERE exists (select x intersect select y)

what is the difference between x = NULL and x IS NULL

在 Snowflake 中就像在其他 RDBMS 中一样,Nothing 等于 NULL(甚至 NULL 本身),因此条件 x = NULL(这是有效的 SQL 语法) 将始终评估为 false(好吧,实际上,在大多数 RDBMS 中它评估为 NULL,这是不正确的)。请注意,对于非相等比较也是如此:即 NULL <> NULL 也是错误的。

检查变量是否为 NULL 的典型方法是使用 x IS NULL 结构,如果 xNULL,则其计算结果为真。您也可以使用 x IS NOT NULL。此语法是为 NULL 保留的,因此 x IS y 是语法错误。

这里是a small demo:

select 
    case when 1 = null then 1 else 0 end 1_equal_null,
    case when 1 <> null then 1 else 0 end 1_not_equal_null,
    case when null is null then 1 else 0 end null_is_null,
    case when 1 is not null then 1 else 0 end 1_is_not_null
1_equal_null | 1_not_equal_null | null_is_null | 1_is_not_null
-----------: | ---------------: | -----------: | ------------:
           0 |                0 |            1 |             1

这种特殊情况在 Snowflake 的文档中有详细描述:

EQUAL_NULL

IS [ NOT ] DISTINCT FROM

Compares whether two expressions are equal. The function is NULL-safe, meaning it treats NULLs as known values for comparing equality. Note that this is different from the EQUAL comparison operator (=), which treats NULLs as unknown values.

+------+------+--------------------------------+------------------------------------------+----------------------------+--------------------------------------+
| X1_I | X2_I | X1.I IS NOT DISTINCT FROM X2.I | SELECT IF X1.I IS NOT DISTINCT FROM X2.I | X1.I IS DISTINCT FROM X2.I | SELECT IF X1.I IS DISTINCT FROM X2.I |
|------+------+--------------------------------+------------------------------------------+----------------------------+--------------------------------------|
|    1 |    1 | True                           | Selected                                 | False                      | Not                                  |
|    1 |    2 | False                          | Not                                      | True                       | Selected                             |
|    1 | NULL | False                          | Not                                      | True                       | Selected                             |
|    2 |    1 | False                          | Not                                      | True                       | Selected                             |
|    2 |    2 | True                           | Selected                                 | False                      | Not                                  |
|    2 | NULL | False                          | Not                                      | True                       | Selected                             |
| NULL |    1 | False                          | Not                                      | True                       | Selected                             |
| NULL |    2 | False                          | Not                                      | True                       | Selected                             |
| NULL | NULL | True                           | Selected                                 | False                      | Not                                  |
+------+------+--------------------------------+------------------------------------------+----------------------------+--------------------------------------+