PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Sprawdź, czy w tablicy Postgres istnieje NULL

Postgres 9.5 lub nowszy

Lub użyj array_position() . Zasadniczo:

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

Zobacz demo poniżej.

Postgres 9.3 lub nowszy

Możesz testować za pomocą wbudowanych funkcji array_remove() lub array_replace() .

Postgres 9.1 lub dowolna wersja

Jeśli wiesz pojedynczy element, który nigdy nie może istnieć w twoich tablicach, możesz użyć tego szybkiego wyrażenie. Powiedzmy, że masz tablicę liczb dodatnich i -1 nigdy w nim nie może być:

-1 = ANY(arr) IS NULL

Powiązana odpowiedź ze szczegółowym wyjaśnieniem:

  • Czy tablica zawiera wszystkie wartości NULL w PostgreSQL

Jeśli nie masz całkowitej pewności , możesz wrócić do jednego z drogich, ale bezpiecznych metody z unnest() . Na przykład:

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

lub:

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

Ale możesz mieć szybko i bezpiecznie z CASE wyrażenie. Użyj mało prawdopodobnej liczby i wróć do bezpiecznej metody, jeśli powinna istnieć. Możesz zająć się sprawą arr IS NULL osobno. Zobacz demo poniżej.

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

Wynik:

 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

Zauważ, że array_remove() i array_position() nie są dozwolone dla tablic wielowymiarowych . Wszystkie wyrażenia na prawo od t_93a działa tylko dla tablic jednowymiarowych.

db<>graj tutaj - Postgres 13, więcej testów
Stary sqlfiddle

Konfiguracja testu porównawczego

Dodane czasy pochodzą z testu porównawczego z 200 tys. wierszy w Postgres 9.5 . Oto moja konfiguracja:

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;

Opakowanie funkcji

Do wielokrotnego użytku , utworzyłbym funkcję w Postgresie 9,5 tak:

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 tylko dla Postgresa 9.6 lub nowszego.

Używając polimorficznego typu danych wejściowych, działa to dla dowolnych typ tablicy, nie tylko int[] .

Zrób to IMMUTABLE aby umożliwić optymalizację wydajności i wyrażenia indeksujące.

  • Czy PostgreSQL obsługuje sortowanie „niewrażliwe na akcenty”?

Ale nie rób tego STRICT , co wyłączyłoby „umieszczanie funkcji” i pogorszyło wydajność, ponieważ array_position() nie jest STRICT samo. Zobacz:

  • Funkcja działa szybciej bez modyfikatora STRICT?

Jeśli chcesz złapać przypadek 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';

Dla Postgresa 9.1 użyj t_91 wyrażenie z góry. Reszta obowiązuje bez zmian.

Ściśle powiązane:

  • Jak ustalić, czy w Postgresie znajduje się tablica NULL?


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Porady i wskazówki dotyczące Postgresa

  2. Jak wysłać zapytanie do wszystkich wierszy w promieniu 5 mil od moich współrzędnych?

  3. Czy można zmienić naturalną kolejność kolumn w Postgresie?

  4. Więcej moich ulubionych zapytań PostgreSQL – i dlaczego one również mają znaczenie

  5. PostgreSQL unnest() z numerem elementu