ASA
ASA

Reputation: 331

Declare variable set = select

How do I declare a variable for used in a PostgreSQL 9.3 query?

CREATE or replace FUNCTION public.test()
  returns int4
AS
$BODY$
DECLARE    
    cod_process bigint :=30001;
    cod_instance bigint ;
    utc_log timestamp without time zone := localtimestamp;
    cod_log_type varchar(100) :='information ';
    txt_log_text varchar(100):= 'start process';
    txt_log varchar(100):= txt_log_text||'_'||cod_process;
    set cod_instance= select max(cod_instance) as cod_instance from public.instance where public.instance.cod_process=cod_process;    
BEGIN  
    INSERT INTO public.log (cod_process, cod_instance, utc_log,cod_log_type,txt_log)
    VALUES (cod_process, cod_instance, utc_log,cod_log_type,txt_log );
    RETURN 11;
END;
$BODY$ LANGUAGE 'plpgsql';
ERROR: type "cod_instance" does not exist
SQL state: 42704
Character: 383

Upvotes: 29

Views: 98219

Answers (2)

Erwin Brandstetter
Erwin Brandstetter

Reputation: 658462

Correct

Your demo function would work like this:

CREATE or REPLACE FUNCTION public.test()
  RETURNS int4
  LANGUAGE plpgsql AS
$func$
DECLARE
   _cod_process  bigint := 30001;
   _cod_instance bigint := (SELECT max(cod_instance)
                            FROM   public.instance
                            WHERE  cod_process = _cod_process);
   _utc_log      timestamp := localtimestamp;
   _cod_log_type varchar(100) := 'information';
   _txt_log_text varchar(100) := 'start process';
   _txt_log      varchar(100) := txt_log_text || '_' || cod_process;
BEGIN
   INSERT INTO public.log
          ( cod_process,  cod_instance,  utc_log,  cod_log_type,  txt_log)
   VALUES (_cod_process, _cod_instance, _utc_log, _cod_log_type, _txt_log);

   RETURN 11;
END
$func$;

Major points

  • You cannot use SET to assign a variable. That's taken to be the SQL command SET for setting run-time parameters.

  • But you can assign a variable at declaration time, even use a subquery for that.

  • @a_horse_with_no_name already wrote about naming conflicts.

  • Using a clean format goes a long way when debugging code ...

Simpler

You can probably simplify to:

CREATE OR REPLACE FUNCTION public.test(_cod_process bigint = 30001)
  RETURNS integer
  LANGUAGE sql AS
$func$
   INSERT INTO public.log
         (cod_process, cod_instance     , utc_log, cod_log_type , txt_log)
   SELECT $1         , max(cod_instance), now()  , 'information', 'start process_' || $1
   FROM   public.instance
   WHERE  cod_process = $1
   GROUP  BY cod_process
   RETURNING 11
$func$;

Call:

SELECT public.test();     -- for default 30001
SELECT public.test(1234);

Depending on the actual data type of utc_log you probably want now() AT TIME ZONE 'UTC'. See:

Upvotes: 40

user330315
user330315

Reputation:

You need to run the select using the into clause inside the actual code block, not in the declare block:

begin
   select max(cod_instance) 
      into cod_instance
   from public.instance 
   where public.instance.cod_process=cod_process;

   ....
end;

It's usually not such a good idea to give variables (or parameters) the same name as columns in the table. There are certain cases where this can confuse the parser. To avoid any potential problems, try to use different names for your variables, e.g. by prefixing them (e.g. l_cod_process instead of cod_process or l_cod_instance instead of cod_instance)

More details on variable assignment can be found in the manual: http://www.postgresql.org/docs/current/static/plpgsql-statements.html

Upvotes: 34

Related Questions