PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Проверете дали NULL съществува в Postgres масива

Postgres 9.5 или по-нова версия

Или използвайте array_position() . По принцип:

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

Вижте демонстрацията по-долу.

Postgres 9.3 или по-нова версия

Можете да тествате с вградените функции array_remove() или array_replace() .

Postgres 9.1 или всяка версия

Ако знате един елемент, който никога не може да съществува във вашите масиви, можете да използвате този бърз изразяване. Да кажем, че имате масив от положителни числа и -1 никога не може да бъде в него:

-1 = ANY(arr) IS NULL
 

Свързан отговор с подробно обяснение:

  • Масивът е всички NULL в PostgreSQL

Ако не можете да сте напълно сигурни , вие можете се върнете към един от скъпите, но безопасни методи с 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);
 

Резултат:

<предварителен> брой | обр | очаквай | 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 5 | {-1,2,3} | е | е | е | е | е | е | е | е | е | е | f 6 | NULL | NULL | т --!! | NULL | е | NULL | NULL | NULL | NULL | е | е | NULL

Обърнете внимание, че array_remove() и array_position() не са разрешени за многомерни масиви . Всички изрази вдясно от t_93a работи само за едномерни масиви.

db<>цигулка тук - Postgres 13, с повече тестове
Стар sqlfiddle

Настройка на сравнителен анализ

Добавените времена са от бенчмарк тест с 200 000 реда в Postgres 9.5 . Това е моята настройка:

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 само за Postgres 9.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 израз отгоре. Останалото важи непроменено.

Тясно свързани:

  • Как да определим дали NULL се съдържа в масив в 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. Редовен израз в клауза LIKE на PostgreSQL

  2. Как Pi() работи в PostgreSQL

  3. Сравняване на хранилища за данни за PostgreSQL - MVCC срещу InnoDB

  4. PostgreSQL - клауза GROUP BY или да се използва в агрегатна функция

  5. Нови и развиващи се функции на PostgreSQL Enterprise с последните версии