PostgreSQL:错误:$ name $不是标量变量

时间:2012-08-30 16:48:08

标签: function postgresql stored-procedures syntax-error plpgsql

有一个函数返回3个参数,其中一个参数是复合类型:

CREATE OR REPLACE FUNCTION f1(
  p_text text,
  OUT result_status_id smallint,
  OUT result_status_msg text,
  OUT result_my_type my_type
  )
  RETURNS record AS
$BODY$
--body here
$BODY$
LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER
  COST 100

复合类型my_type如下所示:

CREATE TYPE my_type AS
   (d_real real,
    d_int1 integer,
    d_int2 integer,
    d_int3 integer,
    d_int4 integer,
    d_int5 integer,
    d_int6 integer,
    d_int7 integer,
    d_int8 integer,
    d_int9 integer,
    d_int10 integer,
    d_bool boolean,
    d_date date,
    d_text text
);

还有另一个函数f2在其体内调用函数f1:

CREATE OR REPLACE FUNCTION f2(
    p_text text
)
  RETURNS record AS
$BODY$
DECLARE
    l_status_id smallint;
    l_status_msg text;
    l_my_type my_type;
BEGIN
--some logic here

--this statement fails
  SELECT * FROM f1(p_text) 'x' 
  INTO l_status_id, l_status_msg, l_my_type;

--logic continues here
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER
  COST 100;

问题是当使用该函数执行sql时,我收到以下错误:

ERROR: "l_my_type" is not a scalar variable

如何从另一个函数中获取复合类型对象?

4 个答案:

答案 0 :(得分:2)

您违反了规则。 The manual:

  

其中 目标 可以是记录变量,行变量或   以逗号分隔的简单变量和记录/行字段列表。

记录或行变量不能成为多项INTO列表的一部分。
解决这个问题的方法之一:

CREATE OR REPLACE FUNCTION f2(p_text text)
  RETURNS record AS
$BODY$
DECLARE
   r            record;
   l_status_id  smallint;
   l_status_msg text;
   l_my_type    my_type;
BEGIN
   SELECT *
   FROM f1(p_text) x  -- don't single quote 'x'
   INTO r;

   l_status_id  := r.result_status_id;
   l_status_msg := r.result_status_msg;
   l_my_type    := r.result_my_type;

  RETURN r; -- or whatever ..
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

还有更多方法。取决于你要去哪里。我几乎没有回复过匿名记录。

答案 1 :(得分:1)

元组中的复合类型是部分支持的东西之一,你会遇到奇怪的问题(特别是像存储这样的问题,但这是另一个故事)。一种方法是:

CREATE TYPE return_type_for_function AS (
       result_status_id smallint,
       result_status_msg text,
       result_my_type my_type
);

CREATE FUNCTION myfunc(....) RETURNS return_type_for_function ....

这是我一直这样做的方式。这比使用OUT变量要成熟一点。

这是一个简单的例子:

or_examples=# create table rel_examples.tabletest (id int);
CREATE TABLE

or_examples=# create table comp_table_test (test rel_examples.tabletest);
CREATE TABLE

or_examples=# create function test(int) returns comp_table_test
immutable language sql as $$
select row(row($1))::comp_table_test; $$;
CREATE FUNCTION
or_examples=# select test(1);
  test   
---------
("(1)")
(1 row)

答案 2 :(得分:1)

然而,@ Chris Travers提出了一个可接受的解决方案,在我的情况下,很遗憾不可能引入一种新类型来从f1函数返回数据。

然而,可以在函数f2()中调用函数f1()并仍使用以下语法获取数据:

CREATE OR REPLACE FUNCTION f2(
    p_text text
)
  RETURNS record AS
$BODY$
DECLARE
    l_status_id smallint;
    l_status_msg text;
    l_my_type my_type;
    l_record record;
BEGIN
--some logic here

--this statement is okay now
  l_record = f1(p_text);
  l_status_id = l_record.result_status_id;
  l_status_msg = l_record.result_status_msg;
  l_my_type = l_record.result_my_type;

--logic continues here
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER
  COST 100;

答案 3 :(得分:0)

在你的f2()函数中,你可以选择一个记录变量,然后从中提取你需要的东西,例如:

CREATE OR REPLACE FUNCTION f2(p_text text )
  RETURNS record AS
$BODY$
DECLARE
    record_var record;
BEGIN
--this statement was failing
  SELECT * FROM f1(p_text) INTO record_var;

 SELECT l_my_type.result_my_type.d_int1; -- this should work

END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER
  COST 100;