0xA*_*xAX 1 postgresql select boolean row plpgsql
我有一个自定义类型:
create type some_type as (
some_bool_param boolean,
str varchar
);
Run Code Online (Sandbox Code Playgroud)
我用这种类型的字段创建一个表并插入一些数据:
create table test_table (
strs some_type
);
insert into test_table(strs) values
((false, 'First str'))
, ((false, 'Second str '))
, ((false, 'Third str'))
, ((false, 'Yet another str'));
Run Code Online (Sandbox Code Playgroud)
现在我尝试返回 setofsome_type
数据:
create or replace function get_str() returns setof some_type as
$$
declare
r some_type;
begin
for r in
select * from test_table loop
return next r;
end loop;
return;
end;
Run Code Online (Sandbox Code Playgroud)
我打电话get_str()
:
select * from get_str();
Run Code Online (Sandbox Code Playgroud)
但是得到一个错误:
Run Code Online (Sandbox Code Playgroud)ERROR: error in boolean type value: "(f,"First str")" CONTEXT: PL/pgSQL function "get_str" line 4 at FOR by result of SELECT
我该如何解决?
create or replace function get_str() returns setof some_type as
$$
declare
r some_type;
begin
for r in
select strs from test_table loop
return next r;
end loop;
return;
end;
Run Code Online (Sandbox Code Playgroud)
以防万一:声明一个表也会声明它的行类型,所以CREATE TYPE
这里不需要单独的。这也可以:
create table test_table (
some_bool_param boolean,
str varchar
);
insert into test_table values (false, 'First str');
insert into test_table values (false, 'Second str ');
insert into test_table values (false, 'Third str');
insert into test_table values (false, 'Yet another str');
create or replace function get_str()
returns setof test_table as
$$
SELECT *
FROM test_table;
$$
LANGUAGE sql;
Run Code Online (Sandbox Code Playgroud)
对于此类函数,您不再需要使用当前版本的 PostgreSQL 的循环。改用RETURN QUERY
:
CREATE OR REPLACE FUNCTION get_str()
RETURNS SETOF test_table AS
$func$
BEGIN
RETURN QUERY
TABLE test_table; -- shorthand for: SELECT * FROM test_table
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
或者像 @Quassnoi 提供的 SQL 函数。请注意,这将返回一个嵌套复合类型(SETOF test_table
,而不是SETOF some_type
)。
奇怪的是,这也有效:
CREATE OR REPLACE FUNCTION get_str5()
RETURNS SETOF some_type AS
$func$
TABLE test_table;
$func$ LANGUAGE sql;
Run Code Online (Sandbox Code Playgroud)
外层行包装器被默默地删除,至少可以说这对 Postgres 来说有点奇怪。
你的函数将像这样工作:
CREATE OR REPLACE FUNCTION get_str()
RETURNS TABLE (strs some_type) AS
$func$
BEGIN
FOR strs IN
SELECT (t.strs).* FROM test_table t
LOOP
RETURN NEXT r;
END LOOP;
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
注意粗体部分。循环中对行或记录类型的分配FOR
是逐个子字段完成的。这通常很方便,但在使用嵌套复合类型时会变得混乱。
some_type
表行 ( ) 内有一个复合类型( test_table
) -两层嵌套。这通常不是人们想要的,但这就是您向我们呈现的。
您需要分解/解开两次。
您的原始代码仅使用 分解外行包装器select * from test_table
。
@Quassnoi 建议的修复select strs from test_table
以同样的方式失败:strs 通过直接引用从表行中分解,但strs
仍然是需要在赋值之前分解自身的行类型。