postgres,null数组vs 0长度数组:它们都返回null = true,但表现不同

时间:2016-08-25 21:24:36

标签: arrays postgresql

内部函数(plpgsql)和代码块我测试了pgsql真的不需要初始化数组。
试试这个:我只是在附加一个元素之前和之后测试数组长度。

do $$ 
declare ai int[];
begin

--BEFORE
raise notice 'ai length: %', array_length(ai,1);

--append the element (to the NON initialized array)
ai = array_append(ai,'2016');

--AFTER
raise notice 'ai length: %', array_length(ai,1);

end;
$$

没有错误,结果是:

NOTICE:  ai length: <NULL>
NOTICE:  ai length: 1

您甚至可以在抛出异常时访问越界元素:

begin
raise notice 'ai length: %', array_length(ai,1);
raise notice 'element 99: %', ai[99];

输出:

  

注意:ai长度:NULL
  注意:元素99:NULL

所以你开始认为数组以某种方式进行了懒惰初始化,只需使用它们。 但情况并非总是如此,请考虑以下代码:

do $$  
  declare ai int[]; 
  declare i int; 

begin

foreach i in array ai loop
    raise notice 'Element: %', i;
end loop;

end; $$

会抛出错误!以下内容:

  

错误:FOREACH表达式不能为空

因此,在某些情况下,数组进行初始化。 让我们检查,让我们发现初始化与非初始化之间的区别:

do $$
declare ai int[];
declare x int;
declare i int;
begin

raise notice 'Array length: %', array_length(ai,1);

ai = array[] :: int[];

raise notice 'Array length: %', array_length(ai,1);

foreach i in array ai loop
    raise notice 'Element: %', i;
end loop;

end;
$$

输出:

  

注意:数组长度:NULL
  注意:数组长度:NULL

所以:行

ai = array[] :: int[];

工作,实际上for循环不再抛出异常。

但是,在初始化之后,

raise notice 'Array length: %', array_length(ai,1);

仍然给'null',这很奇怪。

问题是:我初始化阵列的方式是否正确?
对这种奇怪的行为有解释吗?

(Postgres版本:9.5)

1 个答案:

答案 0 :(得分:2)

在plpgsql函数中,我通常在declare中初始化数组:

declare
    arr int[] = '{}';

非初始化数组当然是null。

要区分空数组和空数组,可以使用cardinality()代替array_length()

with data(ar) as (
    values (array[1]), (array[]::int[]), (null)
)
select ar "array", ar isnull "isnull?", array_length(ar, 1), cardinality(ar)
from data;

 array | isnull? | array_length | cardinality 
-------+---------+--------------+-------------
 {1}   | f       |            1 |           1
 {}    | f       |              |           0
       | t       |              |            
(3 rows)