昨天我在Postgres尝试从统计信息表中过滤出用户ID时遇到了一个奇怪的问题。例如,当我们user_id != 24
时,postgres也会排除user_id
为NULL
的行。
我创建了以下测试代码,显示了相同的结果。
CREATE TEMPORARY TABLE test1 (
id int DEFAULT NULL
);
INSERT INTO test1 (id) VALUES (1), (2), (3), (4), (5), (2), (4), (6),
(4), (7), (5), (9), (5), (3), (6), (4), (3), (7),
(NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL);
SELECT COUNT(*) FROM test1;
SELECT id, COUNT(*) as count
FROM test1
GROUP BY id;
SELECT id, COUNT(*) as count
FROM test1
WHERE id != 1
GROUP BY id;
SELECT id, COUNT(*) as count
FROM test1
WHERE (id != 1 OR id IS NULL)
GROUP BY id;
第一个查询只计算所有行。 第二个计算每个值的数量,包括空值。 第三个排除值1以及所有空值。 第四个是解决值1的问题,仍然包括空值。
对于我正在尝试使用此查询的内容,应始终包含空值。
这项工作是唯一的方法吗?这是预期的Postgres行为吗?
答案 0 :(得分:14)
你的“解决方法”是通常的做法。一切都表现得像预期的那样。
原因很简单:nulls既不等于也不等于任何东西。当你认为null意味着“未知”时,这是有道理的,并且与未知值的比较的真实性也是未知的。
推论是:
null = null
不是真的null = some_value
不是真的null != some_value
不是真的存在两个特殊比较IS NULL
和IS NOT NULL
,用于处理测试列是否为null
。没有其他与null的比较可能是真的。
答案 1 :(得分:1)
IS DISTINCT FROM
谓词就是为此目的而存在的。描述为:
不相等,将null视为普通值
因此只需执行id IS DISTINCT FROM 1
即可。
参考:https://www.postgresql.org/docs/11/functions-comparison.html