关于postgresql:声明变量set = select

Declare variable set = select

这听起来可能是一个非常愚蠢的问题,但是我如何声明一个用于PostgreSQL 9.3查询的变量呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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';
1
2
3
ERROR: TYPE"cod_instance" does NOT exist
SQL state: 42704
CHARACTER: 383


演示功能的工作方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;

要点

  • 不能使用SET来分配变量。这就是用于设置运行时参数的SQL命令SET

  • 但您可以在声明时分配一个变量,甚至为此使用子查询。

  • 使用LANGUAGE plpgsql,而不是LANGUAGE 'plpgsql'。它是一个标识符。

  • @一个没有名字的马已经写了关于命名冲突的文章。

  • 在调试代码时,使用干净的格式有很长的路要走…

但您可能可以简化为:

1
2
3
4
5
6
7
8
9
10
11
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;

呼叫:

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

根据utc_log的实际数据类型,您可能需要now() AT TIME ZONE 'UTC'

  • 在Rails和PostgreSQL中完全忽略时区


您需要在实际代码块内使用into子句运行select,而不是在declare块内:

1
2
3
4
5
6
7
8
BEGIN
   SELECT MAX(cod_instance)
      INTO cod_instance
   FROM public.instance
   WHERE public.instance.cod_process=cod_process;

   ....
END;

给变量(或参数)赋予与表中的列相同的名称通常不是一个好主意。在某些情况下,这可能会混淆解析器。为了避免任何潜在的问题,请尝试对变量使用不同的名称,例如,在变量前面加上前缀(例如,l_cod_process而不是cod_processl_cod_instance而不是cod_instance)。

有关变量分配的更多详细信息,请参见手册:http://www.postgresql.org/docs/current/static/plpgsql-statements.html