PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Periksa apakah NULL ada di array Postgres

Postgres 9.5 atau lebih baru

Atau gunakan array_position() . Pada dasarnya:

SELECT array_position(arr, NULL) IS NOT NULL AS array_has_null

Lihat demo di bawah.

Postgres 9.3 atau lebih baru

Anda dapat menguji dengan fungsi bawaan array_remove() atau array_replace() .

Postgres 9.1 atau versi apa pun

Jika Anda tahu elemen tunggal yang tidak akan pernah ada dalam array Anda, Anda dapat menggunakan cepat ini ekspresi. Katakanlah, Anda memiliki larik bilangan positif, dan -1 tidak pernah bisa di dalamnya:

-1 = ANY(arr) IS NULL

Jawaban terkait dengan penjelasan rinci:

  • Apakah array semua NULL di PostgreSQL

Jika Anda tidak bisa benar-benar yakin , Anda bisa kembali ke salah satu yang mahal tapi aman metode dengan unnest() . Seperti:

(SELECT bool_or(x IS NULL) FROM unnest(arr) x)

atau:

EXISTS (SELECT 1 FROM unnest(arr) x WHERE x IS NULL)

Tetapi Anda dapat memiliki cepat dan aman dengan CASE ekspresi. Gunakan nomor yang tidak mungkin dan kembali ke metode aman jika memang ada. Anda mungkin ingin menangani kasus arr IS NULL terpisah. Lihat demo di bawah.

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);

Hasil:

 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

Perhatikan bahwa array_remove() dan array_position() tidak diperbolehkan untuk array multidimensi . Semua ekspresi di sebelah kanan t_93a hanya bekerja untuk array 1-dimensi.

db<>main biola di sini - Postgres 13, dengan lebih banyak tes
sqlfiddle lama

Penyiapan tolok ukur

Waktu yang ditambahkan berasal dari uji benchmark dengan 200 ribu baris di Postgres 9.5 . Ini adalah pengaturan saya:

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;

Pembungkus fungsi

Untuk penggunaan berulang , saya akan membuat fungsi di Postgres 9.5 seperti ini:

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 hanya untuk Postgres 9.6 atau lebih baru.

Menggunakan jenis input polimorfik ini berfungsi untuk apa saja tipe array, bukan hanya int[] .

Jadikan IMMUTABLE untuk memungkinkan pengoptimalan kinerja dan ekspresi indeks.

  • Apakah PostgreSQL mendukung kumpulan "aksen tidak sensitif"?

Tapi jangan dibuat STRICT , yang akan menonaktifkan "fungsi inlining" dan merusak kinerja karena array_position() bukan STRICT diri. Lihat:

  • Fungsi dijalankan lebih cepat tanpa pengubah STRICT?

Jika Anda perlu menangkap kasus 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';

Untuk Postgres 9.1 gunakan t_91 ekspresi dari atas. Sisanya berlaku tidak berubah.

Berhubungan erat:

  • Bagaimana cara menentukan apakah NULL terkandung dalam array di Postgres?


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. mysql_insert_id alternatif untuk postgresql

  2. Postgres:ERROR:paket yang di-cache tidak boleh mengubah jenis hasil

  3. Bagaimana Cosh() Bekerja di PostgreSQL

  4. Ikhtisar Kemampuan JSON Dalam PostgreSQL

  5. Mencampur gabungan eksplisit dan implisit gagal dengan Ada entri untuk tabel ... tetapi tidak dapat dirujuk dari bagian kueri ini