PL/pgSQL control structures for lists / arrays

2019-03-05 11:47发布

问题:

Is it possible to use something like this in Postgres? This is the example from PL/SQL what I want to do:

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;

Can I declare a list of characters and list of numbers as function input parameters?
I have found some examples with FOREACH element but I don't know how to grab a certain element from number list like in Oracle with p_amount_list(r).

回答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

Major points

  • Oracle's number is numeric in Postgres. But if you don't have fractional digits, you'd rather use int or bigint in Postgres. About type mapping between Oracle and Postgres.

  • Postgres does not have "table types" like Oracle. Use array types, an array of numeric in this case: numeric[].

  • The expression IF p_amount_list <> '{}' ... would rule out NULL and "empty array" alike. No need for a second check like in your original. But the IF is not needed at all. For NULL or empty array, the loop isn't entered anyway.

  • r holds the element itself, not an index to it. (Therefore it must be a matching data type.)

This goes to demonstrate basic syntax of a FOREACH loop in a plpgsql function. Otherwise it would be expensive nonsense, better replaced with a much simpler and faster:

SELECT sum(elem) AS sum_amount
FROM   unnest(p_amount_list) elem;