I'm probably doing something wrong with forming the literal. Suppose I have a simple stored procedure like this:
我可能在形成文字方面做错了。假设我有一个这样的简单存储过程:
CREATE OR REPLACE FUNCTION do_something(input_array composite_type[])
RETURNS SETOF text AS
$BODY$
DECLARE
temp_var composite_type;
BEGIN
FOR temp_var IN SELECT unnest(input_array) LOOP
return next temp_var.message;
END LOOP;
END
$BODY$
LANGUAGE plpgsql;
The composite_type
is defined as:
composite_type定义为:
CREATE TYPE composite_type AS
(message text,
amount numeric(16,2));
Performing a query like this:
执行这样的查询:
SELECT * FROM do_something('{"(test,11)","(test2,22)"}')
Produces this result set:
生成此结果集:
(test,11.00)
(test2,22.00)
Instead of:
test
test2
Is it something wrong with my literal or should I access the message
field in a different way? Thanks for any suggestions.
我的文字是否有问题,还是应该以不同的方式访问消息字段?谢谢你的任何建议。
2 个解决方案
#1
2
How you specify your input appears fine, as the same behaviour is observed with row- and array-constructor syntax:
如何指定输入似乎很好,因为使用行和数组构造函数语法观察到相同的行为:
SELECT * FROM do_something( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
And:
SELECT ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[];
produces:
'{"(test,11.00)","(test2,22.00)"}'
If you add a:
如果你添加一个:
RAISE NOTICE '!%!',temp_var;
inside the loop the output is:
在循环内部输出是:
NOTICE: !("(test,11.00)",)!
NOTICE: !("(test2,22.00)",)!
showing that you're actually getting a tuple with "message" as the tuple text you expected and a null "amount".
显示您实际上正在使用“message”作为您期望的元组文本和null“amount”获取元组。
So. Why?
It's a bit of a subtle one. You're using:
这有点微妙。你正在使用:
SELECT unnest(input_array)
which seems to do what you want, right:
这似乎做你想要的,对:
regress=> SELECT unnest( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
unnest
---------------
(test,11.00)
(test2,22.00)
(2 rows)
... but actually, it's returning a single column of type composite_type
. PL/PgSQL composite type assignment expects one column per type column instead. So the single col is being shoved into 'message' and there is no second col.
...但实际上,它返回的是一个类型为composite_type的列。 PL / PgSQL复合类型赋值需要每个类型列一列。因此,单个col被推入'消息'并且没有第二个col。
Instead, write:
SELECT * FROM unnest(input_array)
to unpack the composite for assignment. Then it works as expected:
解压缩组合以进行分配。然后它按预期工作:
regress=> SELECT * FROM do_something( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
do_something
--------------
test
test2
(2 rows)
If the first field of composite_type
were of a non-text type, you'd get an error that was rather more informative about this.
如果composite_type的第一个字段是非文本类型,那么您将收到一个相关信息更多的错误。
#2
1
Craig explained well a reason for this behave - Assignment variable=value inside FOR statement expects zero nesting. So you should to do:
Craig很好地解释了这种行为的原因 - 在FOR语句中赋值变量=值期望零嵌套。所以你应该这样做:
CREATE OR REPLACE FUNCTION do_something(input_array composite_type[])
RETURNS SETOF text AS $BODY$
DECLARE
temp_var record;
BEGIN
-- unnesting
FOR temp_var IN SELECT (unnest(input_array)).*
LOOP
RETURN NEXT temp_var.message;
END LOOP;
RETURN;
END
$BODY$ LANGUAGE plpgsql;
or -- preferable - newer use SetReturnedFunction inside "column list"
或者 - 更好 - 更新在“列列表”中使用SetReturnedFunction
CREATE OR REPLACE FUNCTION do_something(input_array composite_type[])
RETURNS SETOF text AS $BODY$
DECLARE
temp_var record;
BEGIN
-- SELECT FROM
FOR temp_var IN SELECT * FROM unnest(input_array)
LOOP
RETURN NEXT temp_var.message;
END LOOP;
RETURN;
END
$BODY$ LANGUAGE plpgsql;
#1
2
How you specify your input appears fine, as the same behaviour is observed with row- and array-constructor syntax:
如何指定输入似乎很好,因为使用行和数组构造函数语法观察到相同的行为:
SELECT * FROM do_something( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
And:
SELECT ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[];
produces:
'{"(test,11.00)","(test2,22.00)"}'
If you add a:
如果你添加一个:
RAISE NOTICE '!%!',temp_var;
inside the loop the output is:
在循环内部输出是:
NOTICE: !("(test,11.00)",)!
NOTICE: !("(test2,22.00)",)!
showing that you're actually getting a tuple with "message" as the tuple text you expected and a null "amount".
显示您实际上正在使用“message”作为您期望的元组文本和null“amount”获取元组。
So. Why?
It's a bit of a subtle one. You're using:
这有点微妙。你正在使用:
SELECT unnest(input_array)
which seems to do what you want, right:
这似乎做你想要的,对:
regress=> SELECT unnest( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
unnest
---------------
(test,11.00)
(test2,22.00)
(2 rows)
... but actually, it's returning a single column of type composite_type
. PL/PgSQL composite type assignment expects one column per type column instead. So the single col is being shoved into 'message' and there is no second col.
...但实际上,它返回的是一个类型为composite_type的列。 PL / PgSQL复合类型赋值需要每个类型列一列。因此,单个col被推入'消息'并且没有第二个col。
Instead, write:
SELECT * FROM unnest(input_array)
to unpack the composite for assignment. Then it works as expected:
解压缩组合以进行分配。然后它按预期工作:
regress=> SELECT * FROM do_something( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
do_something
--------------
test
test2
(2 rows)
If the first field of composite_type
were of a non-text type, you'd get an error that was rather more informative about this.
如果composite_type的第一个字段是非文本类型,那么您将收到一个相关信息更多的错误。
#2
1
Craig explained well a reason for this behave - Assignment variable=value inside FOR statement expects zero nesting. So you should to do:
Craig很好地解释了这种行为的原因 - 在FOR语句中赋值变量=值期望零嵌套。所以你应该这样做:
CREATE OR REPLACE FUNCTION do_something(input_array composite_type[])
RETURNS SETOF text AS $BODY$
DECLARE
temp_var record;
BEGIN
-- unnesting
FOR temp_var IN SELECT (unnest(input_array)).*
LOOP
RETURN NEXT temp_var.message;
END LOOP;
RETURN;
END
$BODY$ LANGUAGE plpgsql;
or -- preferable - newer use SetReturnedFunction inside "column list"
或者 - 更好 - 更新在“列列表”中使用SetReturnedFunction
CREATE OR REPLACE FUNCTION do_something(input_array composite_type[])
RETURNS SETOF text AS $BODY$
DECLARE
temp_var record;
BEGIN
-- SELECT FROM
FOR temp_var IN SELECT * FROM unnest(input_array)
LOOP
RETURN NEXT temp_var.message;
END LOOP;
RETURN;
END
$BODY$ LANGUAGE plpgsql;