Postgres 9.5 eller senare
Eller använd array_position()
. I grund och botten:
SELECT array_position(arr, NULL) IS NOT NULL AS array_has_null
Se demo nedan.
Postgres 9.3 eller senare
Du kan testa med de inbyggda funktionerna array_remove()
eller array_replace()
.
Postgres 9.1 eller någon version
Om du vet ett enda element som aldrig kan existera i dina arrayer, kan du använda denna snabb uttryck. Säg att du har en rad positiva tal och -1
kan aldrig vara med i den:
-1 = ANY(arr) IS NULL
Relaterat svar med detaljerad förklaring:
- Är array alla NULLs i PostgreSQL
Om du inte kan vara helt säker , du kunde fall tillbaka till en av de dyra men säkra metoder med unnest()
. Gilla:
(SELECT bool_or(x IS NULL) FROM unnest(arr) x)
eller:
EXISTS (SELECT 1 FROM unnest(arr) x WHERE x IS NULL)
Men du kan ha snabbt och säkert med ett CASE
uttryck. Använd ett osannolikt tal och fall tillbaka till den säkra metoden om den skulle finnas. Du kanske vill behandla fallet arr IS NULL
separat. Se demo nedan.
Demo
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);
Resultat:
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
Observera att array_remove()
och array_position()
är inte tillåtna för flerdimensionella arrayer . Alla uttryck till höger om t_93a
fungerar endast för 1-dimensionella arrayer.
db<>spela här - Postgres 13, med fler tester
Old sqlfiddle
Konfiguration av benchmark
De tillagda tiderna är från ett benchmarktest med 200 000 rader i Postgres 9.5 . Det här är min inställning:
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;
Funktionsomslag
För upprepad användning , skulle jag skapa en funktion i Postgres 9.5 så här:
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
endast för Postgres 9.6 eller senare.
Genom att använda en polymorf inmatningstyp fungerar detta för alla matristyp, inte bara int[]
.
Gör det IMMUTABLE
för att tillåta prestandaoptimering och indexuttryck.
- Stöder PostgreSQL "accentokänsliga" sammanställningar?
Men gör det inte till STRICT
, vilket skulle inaktivera "function inlining" och försämra prestandan eftersom array_position()
är inte STRICT
sig. Se:
- Funktionen körs snabbare utan STRICT modifierare?
Om du behöver fånga fallet är 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';
För Postgres 9.1 använd t_91
uttryck från ovan. Resten gäller oförändrat.
Närbesläktade:
- Hur avgör man om NULL finns i en array i Postgres?