返回 NULL 的空数组的 array_length()

Posted

技术标签:

【中文标题】返回 NULL 的空数组的 array_length()【英文标题】:array_length() of an empty array returning NULL 【发布时间】:2011-08-08 16:33:48 【问题描述】:

我正在 PL/pgSQL 中开发一些存储过程,其中一些给我带来了一些问题。我正在开发的存储过程通过参数接收一个数组,我在 FOR LOOP 中使用该数组来获取其所有元素。为了定义 FOR LOOP 的上限,我使用了 array_length 函数。

FOR i IN 1..array_length(array,1) LOOP

   --array[i] something in here

END LOOP;

当我给存储过程一个空数组时,就会出现问题。 sproc 不是不进入循环,而是简单地返回一个错误,说明 FOR LOOP 的上限为 NULL。不应该是0吗?

我在 FOR LOOP 上做错了吗?

在使用空数组时,有没有其他方法可以在 LOOP 中使用相同的边界而不返回 NULL?

注意:我知道我总是可以在 LOOP 之前使用条件,如下所示:

IF array_length(array,1) IS NOT NULL THEN

但问题是:这个存储过程应该在最短的时间内处理数千个调用。因此,我不希望在处理中增加不必要的开销。我只是在寻找是否有任何方法可以在 LOOP 中“循环”一个空数组。

【问题讨论】:

【参考方案1】:

与往常一样,如果您希望 NULL 值具有不同的行为,请使用 coalesce 构造:

FOR i IN 1..coalesce(array_length(array, 1), 0) LOOP
    RAISE NOTICE '%', array[i];
END LOOP;

关于返回值:array_length(x, N)返回Nth维度的元素个数。由于空数组没有维度,因此它返回 NULL。你说得对,如果你只考虑简单的数组是违反直觉的,但对多维数组来说是有意义的。

编辑:就像 Erwin Brandstetter 在 cmets 中所写,使用 array_lower/upper 循环遍历数组索引更正确。这些将适用于不是基于 1 的数组。这些也需要一个维度参数并需要合并:

FOR i IN coalesce(array_lower(array, 1), 1)..coalesce(array_upper(array, 1), 1) LOOP
    RAISE NOTICE '%', array[i];
END LOOP;

【讨论】:

由于 Postgres 支持 arbitrary array subscripts,此表单仍然不是 100% 安全的。您必须使用array_lower()array_upper() 才能确定。 对于上限,不应该是 coalesce(array_upper(array, 1), 0) 吗?因为 1 .. 1 仍然会使其进入循环一次。【参考方案2】:

通过使用 FOREACH 循环遍历数组来完全避免这个问题,这是 Postgres 9.1 引入的:

FOREACH i IN ARRAY $1
LOOP
   -- do something
END LOOP;

根据您想要在循环中执行的操作,您可能能够完全避免循环并使用带有unnest() 的普通SQL。基于集合的操作通常比 PostgreSQL 中的循环更快。

例子:

RETURN QUERY
SELECT elem || 'foo'
FROM unnest($1) AS t(elem);

【讨论】:

以上是关于返回 NULL 的空数组的 array_length()的主要内容,如果未能解决你的问题,请参考以下文章

Java中应该返回零长度数组或空集合,而不是返回null(转)

-[__NSArrayM objectAtIndex:]:索引 0 超出了带有 userInfo 的空数组的界限(null)

为啥使用 null 函数而不是 == [] 来检查 Haskell 中的空列表?

如何写sql语句去掉oracle返回结果中的空值(NULL)

Mongoose populate() 返回没有错误的空数组

绑定到 appsettings.json 中的空数组时的空属性