如何在不使用“列定义列表”的情况下动态检索表中的行?
我试图通过使用多态类型“anyelement”(伪类型)来做同样的但是得到错误“查询结构与函数结果类型不匹配”。
例如:我有一个名为“table1”的表,其中包含以下详细信息。
- 表
create table table1
(
slno integer,
fname varchar,
lname varchar,
city varchar,
country varchar
)
- 功能
create or replace function function1(column_name varchar,relation_name anyelement)
returns setof anyelement as
$fun$
declare
cname varchar;
add_column varchar;
group_column varchar;
select_query varchar;
begin
if column_name='fname' then
cname:=quote_ident(column_name);
add_column:='"city"'||','||'"country"';
group_column:='"slno"'||','||cname||','||'"city"'||','||'"country"';
else
cname:=quote_ident(column_name);
add_column:='"city"'||','||'"country"';
group_column:='"slno"'||','||cname||','||'"city"'||','||'"country"';
end if;
select_query:='select slno,'||cname||','||add_column||' from '||pg_typeof(relation_name) || 'group by '||group_column;
return query execute select_query;
end;
$fun$
language plpgsql;
---函数调用
select * from function1('fname',NULL::table1);
答案 0 :(得分:4)
anyelement
中描述了relation_name
作为返回类型的处理:
当函数的返回值被声明为多态类型时, 必须至少有一个也是多态的参数位置, 并且作为参数提供的实际数据类型确定了 该调用的实际结果类型。
在您的情况下,此参数的anyelement
类型为NULL::table1
,并且通过传递function1
,这确实告诉规划人员SETOF table1
的此特定调用应返回{{ 1}}。到目前为止一切都很好。
现在的问题是,一旦执行,该函数不会返回SETOF table1
,而是返回其他内容。这不是执行者所期待的,因此也就是错误。
尽管问题的标题是如何返回动态行... ,但您似乎想要的是动态列或多态结果集。
这对SQL来说是一场艰苦的战斗,因为为了构建查询的执行计划,计划程序必须知道每个列的每个中间结果的类型。如果您使用必须执行的函数设计查询以查找其输出结构,则会产生鸡和蛋的问题:计划必须先于执行,而不能依赖于它。
由于其动态类型推断技术应用于anyelement
,PostgreSQL已经在推动这个约束实现尽可能多的多态性。
答案 1 :(得分:2)
这是因为如果您使用NULL::table1
的{{1}}值调用您的函数,则必须返回relation_name
。
多态参数和结果相互关联,并在解析调用多态函数的查询时解析为特定的数据类型。声明为anyelement的每个位置(参数或返回值)都允许具有任何特定的实际数据类型,但在任何给定的调用中,它们必须都是相同的实际类型。
http://www.postgresql.org/docs/9.3/static/extend-type-system.html#EXTEND-TYPES-POLYMORPHIC
但你想带着
返回SETOF table1
不是(slno integer, fname varchar, city varchar, country varchar)
的行(错过table1
- 第3列)。
如果您愿意仅使用lname varchar
和'fname'
来调用此功能,那么您的功能可以更加简单:
'lname'
通过这种方式,您可以使用create or replace function function1(
column_name varchar,
relation_name anyelement
)
returns table (
slno integer,
name varchar,
city varchar,
country varchar
)
language plpgsql as
$fun$
begin
return query execute format(
$sql$
select slno, %1$I AS name, city, country
from %2$I
group by slno, %1$I, city, country
$sql$,
column_name,
pg_typeof(relation_name)
);
end;
$fun$;
为NULL::table1
调用您的函数,但是如果您愿意,也可以使用varchar作为relation_name
(这将更具可读性,例如relation_name
1}}参数)。