sql >> データベース >  >> RDS >> PostgreSQL

Postgres配列にNULLが存在するかどうかを確認します

    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が含まれているかどうかを判断するにはどうすればよいですか?


    1. MySQLの日時列から日付を取得する方法

    2. DSNファイルとIRIソフトウェア

    3. 存在しない場合は挿入し、存在しない場合はpostgresqlにIDを返します

    4. Android-SDカード画像をロードする際のより良いアプローチ