Postgres 9.5 ou posterior
Ou use
array_position()
. Basicamente:SELECT array_position(arr, NULL) IS NOT NULL AS array_has_null
Veja demonstração abaixo.
Postgres 9.3 ou posterior
Você pode testar com as funções internas
array_remove()
ou array_replace()
. Postgres 9.1 ou qualquer versão
Se você saber um único elemento que nunca pode existir em seus arrays, você pode usar isso rápido expressão. Digamos que você tenha uma matriz de números positivos e
-1
nunca pode estar nele:-1 = ANY(arr) IS NULL
Resposta relacionada com explicação detalhada:
- É array todos os NULLs no PostgreSQL
Se você não puder ter certeza absoluta , você poderia voltar para um dos caros, mas seguros métodos com
unnest()
. Como:(SELECT bool_or(x IS NULL) FROM unnest(arr) x)
ou:
EXISTS (SELECT 1 FROM unnest(arr) x WHERE x IS NULL)
Mas você pode ter rápido e seguro com um
CASE
expressão. Use um número improvável e volte para o método seguro se ele existir. Você pode querer tratar o caso arr IS NULL
separadamente. Veja demonstração abaixo. Demonstração
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);
Resultado:
num | arr | expect | t_1 | t_2 | t_3 | t_91 | t_93a | t_93b | t_94 | t_95a | t_95b | t_95c -----+-------------+--------+--------+------+-----+------+-------+-------+------+-------+-------+------- 1 | {1,2,NULL} | t | t | t | t | t | t | t | t | t | t | t 2 | {-1,NULL,2} | t | f --!! | t | t | t | t | t | t | t | t | t 3 | {NULL} | t | t | t | t | t | t | t | t | t | t | t 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 | NULL | NULL | t --!! | NULL | f | NULL | NULL | NULL | NULL | f | f | NULL
Observe que
array_remove()
e array_position()
não são permitidos para matrizes multidimensionais . Todas as expressões à direita de t_93a
só funcionam para matrizes unidimensionais. db<>mexa aqui - Postgres 13, com mais testes
Antigo sqlfiddle
Configuração do comparativo de mercado
Os tempos adicionados são de um teste comparativo com 200 mil linhas no Postgres 9.5 . Esta é a minha configuração:
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;
Invólucro de função
Para uso repetido , eu criaria uma função no Postgres 9.5 assim:
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
apenas para Postgres 9.6 ou posterior. Usando um tipo de entrada polimórfico, isso funciona para qualquer tipo de array, não apenas
int[]
. Torne-o
IMMUTABLE
para permitir otimização de desempenho e expressões de índice. - O PostgreSQL suporta agrupamentos "insensíveis ao acento"?
Mas não torne isso
STRICT
, o que desabilitaria o "inlining da função" e prejudicaria o desempenho porque array_position()
não é STRICT
em si. Ver:- A função é executada mais rapidamente sem o modificador STRICT?
Se você precisar pegar o caso
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';
Para Postgres 9.1 use o
t_91
expressão de cima. O resto aplica-se inalterado. Intimamente relacionado:
- Como determinar se NULL está contido em um array no Postgres?