Postgres9.5以降
または、 array_position()
を使用します 。基本的に:
SELECT array_position(arr, NULL) IS NOT NULL AS array_has_null
以下のデモをご覧ください。
Postgres9.3以降
組み込み関数array_remove()
でテストできます またはarray_replace()
。
Postgres9.1または任意のバージョン
知っている場合 配列に存在することのできない単一の要素であるため、この高速を使用できます。 表現。たとえば、正の数の配列があり、-1
決してその中に入ることはできません:
-1 = ANY(arr) IS NULL
詳細な説明付きの関連回答:
- PostgreSQLではすべてのNULLを配列しますか
絶対に確信が持てない場合 、できた 高価だが安全の1つにフォールバックする 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);
結果:
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
array_remove()
に注意してください およびarray_position()
多次元配列には使用できません 。 t_93a
の右側にあるすべての式 1次元配列でのみ機能します。
db<>ここでフィドル -Postgres 13、より多くのテスト
古いsqlfiddle
ベンチマークの設定
追加された時間は、Postgres9.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
Postgres9.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
を使用する 上からの表現。残りは変更なしで適用されます。
密接に関連している:
- Postgresの配列にNULLが含まれているかどうかを判断するにはどうすればよいですか?