如何从函数中返回表格的行类型和附加列?

时间:2017-06-28 00:15:55

标签: postgresql plpgsql return-type set-returning-functions

我有一个像这样定义的表:

create table users (
  id serial primary key,
  name text,
  email text,
);

...我想编写一个返回形状行的函数:

(
  id integer,
  name text,
  email text,
  some_other_column boolean,
)

我设法使用下面的代码,但我不想重新定义users表中的列:

create or replace function get_users () 
returns table (
  id integer,
  name text,
  email text,
  some_other_column boolean,
) as $$
    select users.*, true as some_other_column from users;
$$ language sql;

有没有办法通过这样做来动态创建行类型? (postgres抱怨users.*处的语法错误):

create or replace function get_users () 
returns table (
  users.*, 
  some_other_column boolean
) as $$
    select users.*, true as some_other_column from users;
$$ language sql;

请注意,以下执行的查询可以直接使用:

select users.*, true as some_other_column from users;

这里的最终目标是最终得到一个可调用的函数,如select * from get_users(),它返回包含现有表和其他列的列的行。我不希望调用者确切地担心如何调用该函数。

我的假设是,因为我可以编写返回动态行的简单sql,所以我应该能够以某种方式将sql存储在数据库中,以保留返回行的结构。

2 个答案:

答案 0 :(得分:2)

否。目前无法做到这一点(包括第10页)。

SQL是一种严格类型的语言。创建函数时,必须声明返回类型。要返回(您可以使用SELECT * FROM srf()调用):

  • 您可以返回匿名记录(RETURNS SETOF record)。但是,您必须在每次调用时提供列定义列表。

  • 您可以返回多态(行)类型(RETURNS SETOF anyelement)。但是你必须提供行类型(composite type)作为函数的参数,行类型需要在系统以某种方式注册

  • 您可以使用RETURNS SETOF rowtype 明确使用任何已注册的行类型。副作用是该函数现在取决于行类型。

  • 您可以使用RETURNS TABLE (...)定义特定的返回行类型 - 您甚至可以在其中混合行类型(composite types)和简单类型。但是简单的SELECT * FROM srf()不会分解嵌套的行类型 - 就像Mabu's answer一样可以证明。

相关:

这一切归结为:

  

有没有办法通过这样做来动态创建行类型?

不,没有。 SELECT * FROM ...将从系统目录中检索列定义列表,其中行类型必须在之前注册,您可以通过这种方式调用函数。

通常,最好在RETURNS TABLE ()子句中拼出列定义列表。这避免了依赖性。如果您需要快速注册基于现有表格的行类型而不拼写其列,则可以创建VIEW - 或TEMPORARY VIEW,如果它仅用于当前会话:< / p>

CREATE TEMP VIEW v_users_plus AS
SELECT *, NULL::boolean AS some_other_column FROM users;

这会在系统中注册同名行(v_users_plus)的行类型,就像任何其他表或视图一样。对于非临时函数,显然您需要非临时行类型。

答案 1 :(得分:0)

您可以将表视为伪类型,但您必须在函数和调用此函数的查询中稍作更改,如下所示。

创建:

create or replace function get_users () 
returns table (
  row_users users, 
  some_other_column boolean
) as $$
    select t, true as some_other_column from users as t;
$$ language sql;

通话:

SELECT (row_users).*, some_other_column FROM get_users();

实际上,您可以尝试使用其他返回类型作为动态结构,例如RefcursorJSON ...这取决于您使用的语言或应用程序。