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)