Postgres 9.5 或更高版本
或使用array_position()。基本上:
SELECT array_position(arr, NULL) IS NOT NULL AS array_has_null
请看下面的演示。
Postgres 9.3 或更高版本
您可以使用内置函数array_remove() 或array_replace() 进行测试。
Postgres 9.1 或任何版本
如果您知道一个永远不会存在于您的数组中的元素,您可以使用这个 fast 表达式。比如说,你有一个正数数组,-1 永远不可能在里面:
-1 = ANY(arr) IS NULL
相关答案及详细解释:
如果您不能绝对确定,您可以使用unnest() 回退到一种昂贵但安全的方法。喜欢:
(SELECT bool_or(x IS NULL) FROM unnest(arr) x)
或:
EXISTS (SELECT 1 FROM unnest(arr) x WHERE x IS NULL)
但是您可以使用CASE 表达式快速安全。使用一个不太可能的数字,如果它应该存在,则回退到安全方法。您可能需要单独处理案例arr IS NULL。请参阅下面的演示。
演示
SELECT num, arr, expect
, -1 = ANY(arr) IS NULL AS t_1 -- 50 ms
, (SELECT bool_or(x IS NULL) FROM unnest(arr) x) AS t_2 -- 754 ms
, EXISTS (SELECT 1 FROM unnest(arr) x WHERE x IS NULL) AS t_3 -- 521 ms
, CASE -1 = ANY(arr)
WHEN FALSE THEN FALSE
WHEN TRUE THEN EXISTS (SELECT 1 FROM unnest(arr) x WHERE x IS NULL)
ELSE NULLIF(arr IS NOT NULL, FALSE) -- catch arr IS NULL -- 55 ms
-- ELSE TRUE -- simpler for columns defined NOT NULL -- 51 ms
END AS t_91
, array_replace(arr, NULL, 0) <> arr AS t_93a -- 99 ms
, array_remove(arr, NULL) <> arr AS t_93b -- 96 ms
, cardinality(array_remove(arr, NULL)) <> cardinality(arr) AS t_94 -- 81 ms
, COALESCE(array_position(arr, NULL::int), 0) > 0 AS t_95a -- 49 ms
, array_position(arr, NULL) IS NOT NULL AS t_95b -- 45 ms
, CASE WHEN arr IS NOT NULL
THEN array_position(arr, NULL) IS NOT NULL END AS t_95c -- 48 ms
FROM (
VALUES (1, '{1,2,NULL}'::int[], true) -- extended test case
, (2, '{-1,NULL,2}' , true)
, (3, '{NULL}' , true)
, (4, '{1,2,3}' , false)
, (5, '{-1,2,3}' , false)
, (6, NULL , null)
) t(num, arr, expect);
结果:
数字 | arr |期待 | t_1 | t_2 | t_3 | t_91 | t_93a | t_93b | t_94 | t_95a | t_95b | t_95c
-----+-------------+--------+--------+------+----- +-----+-------+-------+------+-------+-------+--- ----
1 | {1,2,NULL} |吨 |吨 |吨 |吨 |吨 |吨 |吨 |吨 |吨 |吨 |吨
2 | {-1,NULL,2} |吨 | f --!! |吨 |吨 |吨 |吨 |吨 |吨 |吨 |吨 |吨
3 | {NULL} |吨 |吨 |吨 |吨 |吨 |吨 |吨 |吨 |吨 |吨 |吨
4 | {1,2,3} | f | f | f | f | f | f | f | f | f | f | F
5 | {-1,2,3} | f | f | f | f | f | f | f | f | f | f | F
6 |空 |空 | t --!! |空 | f |空 |空 |空 |空 | f | f |空
请注意,多维数组不允许使用array_remove() 和array_position()。 t_93a 右侧的所有表达式仅适用于一维数组。
dbfiddle here - Postgres 13,有更多测试
旧 sqlfiddle
基准设置
增加的时间来自 Postgres 9.5 中 200k 行的基准测试。这是我的设置:
CREATE TABLE t AS
SELECT row_number() OVER() AS num
, array_agg(elem) AS arr
, bool_or(elem IS NULL) AS expected
FROM (
SELECT CASE WHEN random() > .95 THEN NULL ELSE g END AS elem -- 5% NULL VALUES
, count(*) FILTER (WHERE random() > .8)
OVER (ORDER BY g) AS grp -- avg 5 element per array
FROM generate_series (1, 1000000) g -- increase for big test case
) sub
GROUP BY grp;
函数封装
对于重复使用,我会在 Postgres 9.5 中创建一个函数,如下所示:
CREATE OR REPLACE FUNCTION f_array_has_null (anyarray)
RETURNS bool
LANGUAGE sql IMMUTABLE PARALLEL SAFE AS
'SELECT array_position($1, NULL) IS NOT NULL';
PARALLEL SAFE 仅适用于 Postgres 9.6 或更高版本。
使用polymorphic 输入类型,这适用于任何 数组类型,而不仅仅是int[]。
设为IMMUTABLE 以允许性能优化和索引表达式。
但不要设为STRICT,这会禁用“函数内联”并影响性能,因为array_position() 本身不是STRICT。见:
如需抓案arr IS NULL:
CREATE OR REPLACE FUNCTION f_array_has_null (anyarray)
RETURNS bool
LANGUAGE sql IMMUTABLE PARALLEL SAFE AS
'SELECT CASE WHEN $1 IS NOT NULL
THEN array_position($1, NULL) IS NOT NULL END';
对于 Postgres 9.1,使用上面的 t_91 表达式。其余部分不变。
密切相关: