数组在PostgreSQL中都是NULL

时间:2011-07-27 23:09:27

标签: sql arrays postgresql null

如果PostgreSQL数组的所有元素都为NULL,是否有表达式返回TRUE?

如果它是NULL以外的值,我当然可以使用类似的东西:

SELECT 4 = ALL (ARRAY[4,5]::integer[]);

但是我希望使用IS NULL测试进行ALL操作,而不是= 4测试。我不认为这有一个ALL语法,并且NULL周围的语义与数组复合我自己无法想到实现它的形式。因此我问Stack Overflow。 ; - )

我知道我可以在pl / sql或pl / pgsql中编写一个函数来执行此操作,但是我想在使用它之前看看是否有直接表达式。

5 个答案:

答案 0 :(得分:8)

我认为我得到了最短的答案,同时仍保留4 = ALL (ARRAY[4,5]::integer[]);构造:

实时测试:https://www.db-fiddle.com/f/6DuB1N4FdcvZdxKiHczu5y/1

select
y, true = ALL (select unnest(z) is null)
from x

答案 1 :(得分:8)

1 = ALL(arr) IS NULL AND 2 = ALL(arr) IS NULL

12可以任意两个不同的数字。

替代方案和表现

有两种方法。我组装了一个测试用例,看看哪个是最快的:

SELECT arr
     , 1 = ALL(arr) IS NULL AND 2 = ALL(arr) IS NULL      AS chk_simpl
     , TRUE = ALL (SELECT unnest(arr) IS NULL)            AS chk_michael
     , (SELECT bool_and(e IS NULL) FROM unnest(arr) e)    AS chk_bool_and
     , NOT EXISTS (SELECT unnest(arr) EXCEPT SELECT null) AS chk_exist
FROM  (
   VALUES
     ('{[1,2,NULL,3}'::int[])
    ,('{1,1,1}')
    ,('{2,2,2}')
    ,('{NULL,NULL,NULL]}'::int[])
   ) t1(arr);

第二个来自currently accepted answer by @michael。 列按表达式的性能顺序排列。最快的。我建议的表达式实际上比其他表达快很多次。因此,我的答案。

SQL Fiddle with demo & performance test.

它是如何运作的?

表达式1 = ALL(arr)产生

TRUE ..如果所有元素都是1
FALSE ..如果任何元素是<> 1IS NOT NULL)的任何元素 NULL ..如果至少有一个元素IS NULL且没有元素是<> 1

因此,如果我们知道无法显示的单个元素,例如-1,我们可以简化为:

-1 = ALL(arr) IS NULL

如果任何号码可以显示,请检查两个不同的号码。如果数组只包含NULL,则结果只能为NULL。瞧。

答案 2 :(得分:2)

我并不为此感到自豪,但是:

=> select not exists (
    select 1
    from (select all unnest(ARRAY[NULL, NULL, NULL]) is null as x) as dt
    where x = 'f'
);
 ?column? 
----------
 t
(1 row)

=> select not exists (
    select 1
    from (select all unnest(ARRAY[NULL, 11, NULL]) is null as x) as dt
    where x = 'f'
);
 ?column? 
----------
 f
(1 row)

是的,有很多子查询,但也许你可以使它工作或简化为可行的东西。

答案 3 :(得分:2)

另一种缩短代码的方法,使用每个聚合函数

create table x
(
y serial,
z int[]
);

insert into x(z) values(array[null,null,null]::int[])
insert into x(z) values(array[null,7,null]::int[])
insert into x(z) values(array[null,3,4]::int[])
insert into x(z) values(array[null,null,null,null]::int[])


with a as
(
    select y, unnest(z) as b
    from x
)
select y, every(b is null)
from a 
group by y
order by y

输出:

 y | every
---+-------
 1 | t
 2 | f
 3 | f
 4 | t
(4 rows)

另一种方法,生成用于比较的NULL:

select  y, 
    z = 
    (select array_agg(null::int) 
     from generate_series(1, array_upper(z, 1) )) as IsAllNulls
from    x

上面代码的基础逻辑,返回true:

SELECT ARRAY[NULL,NULL]::int[] = ARRAY[NULL,NULL]::int[]

另一种方法,使用array_fill

select  y, z = array_fill(null::int, array[ array_upper(z, 1) ] )
from    x

警告,数组构造和数组_fill不是对称的,测试这些:

select array[5]

-- array[5] here has different meaning from array[5] above
select array_fill(null::int, array[5]) 

答案 4 :(得分:1)

仅仅为了各种选择,我之前使用的是:

select array_remove(ARRAY[null::int, null, null], null) = '{}'

此方法对于数组中的任何值都将返回true,这在优先存储空值而不是空或所有空数组时非常有用,例如在更新时触发器中:

NEW.arrvalue := CASE WHEN array_remove(NEW.arrvalue, null) <> '{}' THEN NEW.arrvalue END;