Структуры управления PL/pgSQL для списков/массивов

Можно ли использовать что-то подобное в Postgres? Это пример из PL/SQL, что я хочу сделать:

PROCEDURE CREATE_PAYMENT(P_AMOUNT IN NUMBER,
                         P_INVOICE_LIST IN SIMPLEARRAYTYPE, 
                         P_AMOUNT_LIST IN NUMBER_TABLE -- pass list of amounts
                            .
                            .
                            .)

s_chk_amnt              NUMBER;

invoice_list SIMPLEARRAYTYPE;
amount_list NUMBER_TABLE;

BEGIN
      -- check if amount list is null or contains zeros
    IF p_amount_list IS NOT NULL AND p_amount_list.COUNT <> 0 THEN
      FOR r IN p_amount_list.FIRST..p_amount_list.LAST
      LOOP
        s_chk_amnt := s_chk_amnt + p_amount_list(r);
      END LOOP;
    END IF;

Могу ли я объявить список символов и список чисел в качестве входных параметров функции?
Я нашел несколько примеров с FOREACH element, но я не знаю, как получить определенный элемент из списка чисел, как в Oracle с p_amount_list(r).


person Maki    schedule 30.12.2014    source источник
comment
Более подробное объяснение того, что это делает, без ссылки на специфику Oracle, может дать вам лучший ответ.   -  person Craig Ringer    schedule 30.12.2014


Ответы (1)


CREATE OR REPLACE FUNCTION CREATE_PAYMENT(p_amount_list numeric[])
  RETURNS numeric AS
$func$
DECLARE
   s_chk_amnt numeric := 0; -- init variable!
   r          numeric;
BEGIN
-- IF p_amount_list <> '{}' THEN  -- just noise
   FOREACH r IN ARRAY p_amount_list
   LOOP
      s_chk_amnt := s_chk_amnt + r;
   END LOOP;
-- END IF;

RETURN s_chk_amnt;
END
$func$ LANGUAGE plpgsql

Основные моменты

  • number Oracle — это numeric в Postgres. Но если у вас нет дробных цифр, лучше использовать int или bigint в Postgres. О сопоставлении типов между Oracle и Postgres.

  • В Postgres нет "типов таблиц", как в Oracle. Используйте типы массивов, массив из numeric, в данном случае: numeric[].

  • Выражение IF p_amount_list <> '{}' ... исключает как NULL, так и "пустой массив". Нет необходимости во второй проверке, как в вашем оригинале. Но IF вообще не нужен. Для NULL или пустого массива цикл все равно не запускается.

  • r содержит сам элемент, а не его индекс. (Поэтому это должен быть соответствующий тип данных.)

Это демонстрирует базовый синтаксис цикла FOREACH в функции plpgsql. В противном случае это была бы дорогая ерунда, которую лучше заменить гораздо более простой и быстрой:

SELECT sum(elem) AS sum_amount
FROM   unnest(p_amount_list) elem;
person Erwin Brandstetter    schedule 31.12.2014
comment
А что, если я хочу передать список символов? Могу ли я использовать любой массив или? - person Maki; 07.01.2015
comment
Должна ли процедура быть такой в ​​этом случае? - person Maki; 07.01.2015
comment
СОЗДАТЬ ИЛИ ЗАМЕНИТЬ ФУНКЦИЮ CREATE_PAYMENT3(p_inv_list anyarray) ВОЗВРАЩАЕТ anyarray AS $func$ DECLARE s_inv text; -- переменная инициализации! р текст; НАЧАТЬ FOREACH r В МАССИВЕ p_inv_list LOOP s_inv := s_inv || р; КОНЕЦ ПЕТЛИ; ВОЗВРАТ s_inv; КОНЕЦ $func$ ЯЗЫК plpgsql - person Maki; 07.01.2015