2012-08-30 38 views
2

有一个返回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 

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

回答

2

你违反了规则。 The manual:

where target can be a record variable, a row variable, or a comma-separated list of simple variables and record/row fields.

一个记录或者行变量不能是多个项目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; 

有更多的方法。这取决于你要去哪里。我几乎没有回到匿名记录。

+0

这也没关系,它在x附近没有单引号。没有别名功能也是 – Tim

+0

重要的部分是你遇到的错误的解释(对你*和*普通大众)。如前所述,它有多种方式。在你已经发布简单任务后,我选择了一个不同的例子。 –

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;  
+0

不幸的是,这并没有为我工作 – Tim

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) 
+0

+1为一个可接受的解决方案,但我找到了你可以在我的答案找到的技巧 – Tim

1

然而,@克里斯特拉弗斯提出可接受的解决方案,在我的情况下,它是不幸的是没有可能引入新的类型,从f1函数返回的数据。

尽管如此,人们可以使用以下语法调用函数f1()的函数f2(),仍然可以得到数据:

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; 
+0

这是更简单的形式,是的。在另一个注释中:plpgsql中的赋值运算符是':='。为了达到目的,'='运算符没有记录。考虑这个[相关问题](http://stackoverflow.com/q/7462322/939860)。 –