Postgres 9.5 eller nyere
Eller brug array_position()
. Grundlæggende:
SELECT array_position(arr, NULL) IS NOT NULL AS array_has_null
Se demoen nedenfor.
Postgres 9.3 eller nyere
Du kan teste med de indbyggede funktioner array_remove()
eller array_replace()
.
Postgres 9.1 eller en hvilken som helst version
Hvis du ved det et enkelt element, der aldrig kan eksistere i dine arrays, kan du bruge denne hurtige udtryk. Lad os sige, at du har en række positive tal og -1
kan aldrig være i det:
-1 = ANY(arr) IS NULL
Relateret svar med detaljeret forklaring:
- Er array alle NULL'er i PostgreSQL
Hvis du ikke kan være helt sikker , du kunne fald tilbage til en af de dyre, men sikre metoder med unnest()
. Ligesom:
(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 få hurtigt og sikkert med en CASE
udtryk. Brug et usandsynligt tal og fald tilbage til den sikre metode, hvis den skulle eksistere. Du ønsker måske at behandle sagen arr IS NULL
separat. Se demoen nedenfor.
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
Bemærk at array_remove()
og array_position()
er ikke tilladt for flerdimensionelle arrays . Alle udtryk til højre for t_93a
virker kun for 1-dimensionelle arrays.
db<>spil her - Postgres 13, med flere test
Gamle sqlfiddle
Benchmark-opsætning
De tilføjede tider er fra en benchmark-test med 200.000 rækker i Postgres 9.5 . Dette er min opsætning:
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;
Funktionsindpakning
Til gentagen brug , ville jeg oprette en funktion i Postgres 9.5 sådan her:
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
kun til Postgres 9.6 eller nyere.
Ved at bruge en polymorf inputtype virker dette for alle matrixtype, ikke kun int[]
.
Gør det IMMUTABLE
for at tillade ydeevneoptimering og indeksudtryk.
- Understøtter PostgreSQL "accentufølsomme" sammenstillinger?
Men gør det ikke til STRICT
, hvilket ville deaktivere "function inlining" og forringe ydeevnen, fordi array_position()
er ikke STRICT
sig selv. Se:
- Funktionen udføres hurtigere uden STRICT modifier?
Hvis du har brug for at fange sagen 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';
Til Postgres 9.1 brug t_91
udtryk fra oven. Resten gælder uændret.
Nært beslægtet:
- Hvordan bestemmer man, om NULL er indeholdt i et array i Postgres?