Search code examples
arrayspostgresqlparameters

My function with array as parameter does not work


I proceed to specify my question and the solution I gave to the problem, for the benefit of the community. I was trying to perform a multi-column insert using the identifier with a function. For which, I was getting an error, my code was the following:

CREATE OR REPLACE FUNCTION acc.asignar_periodo(ids NUMERIC[], periodo INTEGER,codigo_subdiario VARCHAR) 
  RETURNS void 
  VOLATILE 
AS
$$
DECLARE
cant_registros integer:= 0;
BEGIN
    cant_registros := array_length(ids,1);
    FOR i IN 1..cant_registros LOOP
        EXECUTE'UPDATE '||$3||' SET periodo_tributario = $2  WHERE id = ids[i]';
    END LOOP;
END;
$$ LANGUAGE plpgsql;

and my query is:

SELECT acc.asignar_periodo('{2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302}'::NUMERIC[],201612,'_08');

My solution was the following:

CREATE OR REPLACE FUNCTION acc.asignar_periodo(INTEGER[],INTEGER,INTEGER) RETURNS text VOLATILE AS
$$
DECLARE
qty integer:= array_length($1,1);
respuesta varchar := null;
BEGIN
    FOR i IN 1..qty LOOP
        EXECUTE'UPDATE _'||$3||' SET periodo_tributario = '||$2||' WHERE id = '||$1[i];
    END LOOP;
    respuesta := 'Periodo '||$2||' asignado a '||qty||' comprobantes del subdiario '||$3;
RETURN respuesta;

END;
$$ LANGUAGE plpgsql;

Note the correction, since when using EXECUTE it is necessary that the arguments escape the statements


Solution

  • There is no to loop needed to process the array. Postgres will process the entry array at once. After all set processing is what SQL is all about. Get into the mindset that whenever you write loop, likely incorrect and much slower. (Yes there occasions where it is necessary, but very few.) So: (see demo)

    create or replace function asignar_periodo(ids numeric[], periodo integer,codigo_subdiario varchar) 
       returns void 
      language plpgsql
    as $$
    declare 
       stmt constant text = 'update %I set periodo_tributario = %s where id = any (''%s'')'; 
       torun text; 
    begin
        --torun = format(stmt, $3, $2, $1);                      -- this would work but 
        torun = format(stmt, codigo_subdiario, periodo, ids);    -- I perfer parameter names to position reference
        raise notice '%', torun; 
        execute torun;
    end ;
    $$;