Array_length() пустого массива, возвращающего NULL

Я разрабатываю некоторые хранимые процедуры в PL/pgSQL, и некоторые из них дают мне некоторые проблемы. Продромы, которые я разрабатываю, получают по параметру массив, который я использую в FOR LOOP, чтобы получить все его элементы. Чтобы определить верхнюю границу FOR LOOP, я использую функцию array_length.

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

   --array[i] something in here

END LOOP;

Проблемы возникают, когда я даю sprocs пустой массив. Вместо того, чтобы не вводить цикл, sproc просто возвращает ошибку, заявляя, что верхняя граница FOR LOOP равна NULL. Не должно быть 0?

Я делаю что-то не так с FOR LOOP?

Есть ли другой способ использовать те же границы в LOOP, не возвращая NULL при использовании пустого массива?

Примечание. Я знаю, что всегда могу использовать условие до LOOP, например:

IF array_length(array,1) IS NOT NULL THEN

но проблема заключается в следующем: этот sproc должен обрабатывать тысячи вызовов за короткий промежуток времени. Таким образом, я не ищу что-то, что добавляет ненужные накладные расходы на обработку. Я просто смотрю, есть ли способ "закодировать" пустой массив в 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. Вы правы, что это противоречиво, если вы рассматриваете только простые массивы, но имеет смысл для многомерных массивов.

Изменить: Как писал Эрвин Брандштетер в комментариях, правильнее использовать массивы 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;

Ответ 2

Избегайте проблемы, перейдя через массив с помощью FOREACH, представленной с помощью Postgres 9.1

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

В зависимости от того, что вы хотите сделать в цикле, вы можете вообще избежать цикла и использовать простой SQL с unnest(). Операции с настройками обычно быстрее, чем циклические в PostgreSQL.

Пример:

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