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 или всяка версия
Ако знате един елемент, който никога не може да съществува във вашите масиви, можете да използвате този бърз изразяване. Да кажем, че имате масив от положителни числа и -1
никога не може да бъде в него:
-1 = ANY(arr) IS NULL
Свързан отговор с подробно обяснение:
- Масивът е всички NULL в PostgreSQL
Ако не можете да сте напълно сигурни , вие можете се върнете към един от скъпите, но безопасни методи с 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);
Резултат:
<предварителен> брой | обр | очаквай | 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 5 | {-1,2,3} | е | е | е | е | е | е | е | е | е | е | f 6 | NULL | NULL | т --!! | NULL | е | NULL | NULL | NULL | NULL | е | е | NULL
Обърнете внимание, че array_remove()
и array_position()
не са разрешени за многомерни масиви . Всички изрази вдясно от t_93a
работи само за едномерни масиви.
db<>цигулка тук - Postgres 13, с повече тестове
Стар sqlfiddle
Настройка на сравнителен анализ
Добавените времена са от бенчмарк тест с 200 000 реда в Postgres 9.5 . Това е моята настройка:
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 или по-нова версия.
Използвайки полиморфен входен тип, това работи за всеки тип масив, а не само int[]
.
Направете го IMMUTABLE
за да позволи оптимизиране на производителността и индексни изрази.
- Поддържа ли PostgreSQL съпоставяне с „нечувствителни на акценти“?
Но не го правете STRICT
, което би деактивирало „вграждането на функции“ и би влошило производителността, защото array_position()
не е STRICT
себе си. Вижте:
- Функцията се изпълнява по-бързо без модификатор 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
израз отгоре. Останалото важи непроменено.
Тясно свързани:
- Как да определим дали NULL се съдържа в масив в Postgres?