web-dev-qa-db-fra.com

Déclarer l'ensemble de variables = sélectionner

Cela ressemble probablement à une question vraiment stupide, mais comment déclarer une variable à utiliser dans une requête PostgreSQL 9.3?

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
13
ASA

Vous devez exécuter la sélection à l'aide de la clause into à l'intérieur du bloc de code réel, pas dans le bloc declare:

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

   ....
end;

Ce n'est généralement pas une bonne idée de donner aux variables (ou paramètres) le même nom que les colonnes du tableau. Il existe certains cas où cela peut perturber l'analyseur. Pour éviter tout problème potentiel, essayez d'utiliser des noms différents pour vos variables, par ex. en les préfixant (par exemple l_cod_process au lieu de cod_process ou l_cod_instance au lieu de cod_instance)

Plus de détails sur l'affectation des variables peuvent être trouvés dans le manuel: http://www.postgresql.org/docs/current/static/plpgsql-statements.html

20

Votre fonction de démonstration fonctionnerait comme ceci:

CREATE or replace FUNCTION public.test()
  RETURNS int4 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$ LANGUAGE plpgsql;

Points majeurs

  • Vous ne pouvez pas utiliser SET pour affecter une variable. Il s'agit de la commande SQL SET pour définir les paramètres d'exécution.

  • Mais vous pouvez affecter une variable au moment de la déclaration, même utiliser une sous-requête pour cela.

  • Utilisez LANGUAGE plpgsql, Pas LANGUAGE 'plpgsql'. C'est un identifiant.

  • @ a_horse_with_no_name a déjà écrit sur les conflits de nommage.

  • L'utilisation d'un format propre va un long chemin lors du débogage du code ...


Mais vous pouvez probablement simplifier pour:

CREATE OR REPLACE FUNCTION public.test(_cod_process bigint = 30001)
  RETURNS integer 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$ LANGUAGE sql;

Appel:

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

Et selon le type de données réel de utc_log, Vous voudrez probablement now() AT TIME ZONE 'UTC':

23
Erwin Brandstetter