sql >> Databáze >  >> RDS >> PostgreSQL

Zkontrolujte, zda v poli Postgres existuje NULL

Postgres 9.5 nebo novější

Nebo použijte array_position() . V podstatě:

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

Viz ukázka níže.

Postgres 9.3 nebo novější

Můžete testovat pomocí vestavěných funkcí array_remove() nebo array_replace() .

Postgres 9.1 nebo jakákoli verze

Pokud víte jeden prvek, který nikdy nemůže existovat ve vašich polích, můžete použít toto rychle výraz. Řekněme, že máte pole kladných čísel a -1 nikdy v něm nemůže být:

-1 = ANY(arr) IS NULL

Související odpověď s podrobným vysvětlením:

  • Je pole všechny NULL v PostgreSQL

Pokud si nemůžete být absolutně jisti , mohli byste vrátit se k jednomu z drahých, ale bezpečných metody s unnest() . Jako:

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

nebo:

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

Ale můžete to mít rychle a bezpečně s CASE výraz. Použijte nepravděpodobné číslo a vraťte se k bezpečné metodě, pokud by měla existovat. Možná budete chtít ošetřit případ arr IS NULL odděleně. Viz ukázka níže.

Ukázka

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

Výsledek:

 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

Všimněte si, že array_remove() a array_position() nejsou povoleny pro vícerozměrná pole . Všechny výrazy napravo od t_93a fungují pouze pro 1-dimenstiální pole.

db<>zde hrajte - Postgres 13 s více testy
Starý sqlfiddle

Nastavení srovnávacího testu

Přidané časy jsou z benchmark testu s 200 000 řádky v Postgres 9.5 . Toto je moje nastavení:

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;

Obálka funkcí

Pro opakované použití , vytvořil bych funkci v Postgres 9.5 takhle:

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 pouze pro Postgres 9.6 nebo novější.

Při použití polymorfního typu vstupu to funguje pro libovolné typ pole, nejen int[] .

Udělejte to IMMUTABLE umožňující optimalizaci výkonu a indexové výrazy.

  • Podporuje PostgreSQL kolace „necitlivá na akcent“?

Ale nedělejte to STRICT , což by zakázalo „vkládání funkcí“ a zhoršilo výkon, protože array_position() není STRICT sám. Viz:

  • Funkce se provádí rychleji bez modifikátoru STRICT?

Pokud potřebujete zachytit případ 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';

Pro Postgres 9.1 použijte t_91 výraz shora. Zbytek platí beze změny.

Úzce související:

  • Jak zjistit, zda je v poli v Postgresu obsažena hodnota NULL?


  1. Jak vyvinout offline první nativní aplikaci pro Android

  2. ORA-02287:pořadové číslo zde není povoleno

  3. Význam údržby na MSDB

  4. Zkontrolujte, zda pole Postgres JSON obsahuje řetězec