【问题标题】:Why is "AND NOT field = 'value'" filtering out nulls?为什么“AND NOT field = 'value'”会过滤掉空值?
【发布时间】:2021-05-09 01:57:01
【问题描述】:

我的查询看起来基本上像

WITH DATA AS(
 SELECT fields
    FROM table
        WHERE [many conditions]
        AND NOT field1 = 'string'           
)

SELECT foo,
    bar,
    CASE
        WHEN field1 IS NULL THEN 'other_string'
        [other cases]
    END
FROM data

还有很多其他的东西,但这是不起作用的核心部分。这应该给我很多结果。但是,该特定情况的结果为零;如果我删除其余的查询并基本上只运行这个,它只是一个空表。

AND NOT field1 = 'string' 似乎过滤掉了 field1 为“字符串”的所有行,但也过滤掉了 field1 为空的所有行。如果 field1 为 null,则 field1 = 'string' 应该评估为 false(因为 null 不等于任何值),因此 NOT field1 = 'string' 应该评估 true 并且这些行应该在查询中 - 对吗?

实际上不确定我正在使用的 Redash 前端后面运行的是什么 sql 实现,但我可以确定它是否相关。

【问题讨论】:

  • 因为NOT NULL --> NULL.
  • 您有 WITH DATA(大写),但您的 SELECT 来自 data(小写)。您能否确认这不是导致零结果的不区分大小写的问题? SELECT * from DATA LIMIT 1 基本上有用吗?
  • @tester 是的,改变大小写没有任何作用(即使不匹配,查询也可以正常工作)。
  • 也许可以试试AND field != 'string'
  • @GordonLinoff 我不明白你的评论;据我所知,此查询中没有任何 NOT NULL 。有些东西评估为 NOT FALSE。有什么原因它可能最终变成 NOT NULL 吗?

标签: sql redash


【解决方案1】:

几乎所有与NULL 的比较都会返回NULL。两个突出的例外是 IS NULLIS NOT NULL,它们返回“true”或“false”。

NULL 的语义非常简单:

  • NOT NULL --> NULL
  • TRUE AND NULL --> NULL
  • FALSE AND NULL --> FALSE
  • TRUE OR NULL --> TRUE
  • FALSE OR NULL --> NULL

如果您将NULL 视为表示“*未知”值而不是缺失值,则语义更容易理解。

WHERE 子句仅通过评估为“真”的行。因此,“false”和NULL 都被删除了。请注意,CASE 表达式也是如此。但是,CHECK 表达式将NULL 视为“真”。好吧,从来没有人指责 SQL 的内部一致性。

你的表达是:

WHERE [many conditions] AND NOT field1 = 'string'    

field1NULL 时:

WHERE [many conditions] AND NOT (NULL = 'string')
WHERE [many conditions] AND NOT (NULL)
WHERE [many conditions] AND NULL
WHERE NULL

非常简单的逻辑。

注意:标准 SQL 有一个 NULL 安全比较器,它是:

WHERE [many conditions] AND field1 IS DISTINCT FROM 'string'

一些数据库为此使用<=>

WHERE [many conditions] AND NOT field1 <=>'string'

在其他方面你需要更明确:

WHERE [many conditions] AND (field1 <> 'string' OR field1 IS NULL)

【讨论】:

  • 喜欢,这也让我很生气,因为我不明白为什么 SQL 会说 'string' = NULL 将是 NULL 而不仅仅是错误,因为显然 null 没有意义“等于”任何非空值。但至少我现在知道它是如何工作的。
【解决方案2】:

如果您将NULL 与SQL 中的另一个值进行比较,结果将是NULL。但是,当您使用IS NULLIS NOT NULL 进行显式比较时,将相应地考虑NULL 值。

所以你的情况应该是

(NOT (field1 = 'string') OR field1 IS NULL)

或者也许更易读(&lt;&gt; 表示不等于):

(field1 <> 'string' OR field1 IS NULL)

Here你可以找到一些关于 SQL NULL 值的细节。

无法使用比较运算符(例如 =、)测试 NULL 值。 我们将不得不使用 IS NULL 和 IS NOT NULL 运算符。

【讨论】:

  • “如果将 NULL 与 SQL 中的另一个值进行比较,结果将始终为 false” —> 这是我最初的理解,这就是为什么我按照我的方式编写查询的原因。如果这是真的,那么 field1 = 'string' 将评估为 false 并且我的查询将起作用。您的回答意味着,如果您将 NULL 与另一个值进行比较,则会发生其他事情,而不是 FALSE。显然这不是真的。当然这应该是唯一的两个可能的结果?...
  • 好的,你引用的我的句子可能会产生误导。问题是NOT field1 = 'string' 被评估为一个条件。您假设 field1 = 'string' ist 首先评估,然后由前导 NOT 反转。但它与field1 &lt;&gt; 'string' 的作用相同。如果你写NOT (field1 = 'string'),我不确定会发生什么。但即使这样对于 NULL 也可能是错误的。小故事:只要您期望值可以为 NULL,只需显式测试 NULL。
  • 我刚刚搜索了“与空值比较的 sql 结果”。第一个结果似乎深入处理了您的问题或误解:https://www.xaprb.com/blog/2006/05/18/why-null-never-compares-false-to-anything-in-sql/
猜你喜欢
  • 2022-07-13
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 2012-01-22
  • 2022-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多