3

是否可以在 PostgreSQL 中扩展现有数据类型?本质上,我想要这个 TypeScript 的等价物,但在 SQL 中:

interface Meeting {
  id: number;
  start: Date;
  end: Date;
  description: string;
}

interface ServiceHour extends Meeting {
  total: number;
  hours: number;
}

因为我有一个函数,它返回一个meetings表中的所有列,然后是在查询时计算的另外两个total和列。hours该函数如下所示:

create or replace function user_hours(org_id text, user_id text)
returns table (like meeting_instances)
as $$
select (sum(hours) over (order by _.instance_time)) total, * from (
  select
    extract(epoch from ((meeting_instances.time).to - (meeting_instances.time).from)) / 60 / 60 as hours, 
    meeting_instances.*
  from meeting_instances inner join relation_people on relation_people.meeting = meeting_instances.id
  where relation_people.user = user_id
  and meeting_instances.org = org_id
  and meeting_instances.instance_time <= current_date
) as _;
$$
language sql stable;

现在,我收到类型不匹配错误,因为table (like meeting_instances)它与包含meeting_instances两个新列的hours表不同total。我想要做的是这样的事情(显然下面的语法实际上并不存在......但我不确定是否有另一种方法可以使用类似的速记语法来做到这一点):

returns table (total float, hours float, meeting_instances.*)
returns table (total float, hours float) intersect (like meeting_instances)
returns table (total float, hours float) extends (like meeting_instances)

我目前的解决方法是创建一个视图,然后让该函数简单地查询该视图并返回视图的类型。

4

1 回答 1

4

对于您的核心问题

是否可以扩展现有的数据类型?

,不可能。不在RETURNSPostgreSQLCREATE FUNCTION的 14 版之前,不在任何其他地方。

您可以返回复合类型的字段,以及任何类型的附加字段。但这是微妙的不同:

CREATE FUNCTION user_hours_plus( ...)
  RETURNS TABLE (my_meeting meeting_instances, hours numeric, total numeric) ...

调用该函数:

SELECT * FROM user_hours_plus('a', 'b');

返回嵌套复合类型作为返回列之一,例如:

(1,"2017-01-03","2017-01-04", foo) | 123 | 345

要分解复合类型,您可以调用:

SELECT (my_meeting).*, hours, total FROM user_hours_plus('a', 'b');

但我不会去那里。

我目前的解决方法是创建一个视图,然后让该函数简单地查询该视图并返回视图的类型。

然后只需使用视图。不要在其之上创建附加功能。结案。

如果你真的想说:

RETURNS...然后在函数的子句中使用视图的行类型

然后我们回到你的问题。CREATE VIEW(隐式)注册扩展的行类型是一个有效的选项 - 特别是因为SELECT *它是 had 的情况的一种方便的语法简写。但对于初学者来说,

RETURNS TABLE (LIKE meeting_instances)

... 没有记录的语法CREATE FUNCTION没有人应该使用它。可能会在下一版本之一中删除,恕不另行通知。
规范的、等效的、记录在案的语法是:

RETURNS SETOF meeting_instances

(LIKE some_table)记录了CREATE TABLE. 当前的RETURNS子句CREATE FUNCTION支持相同,但没有记录,所以不要使用它。

回到创建VIEW. VIEW如果除了注册该扩展行类型之外,您对 没有用处,请考虑CREATE TYPE改用。不幸的是,CREATE TYPE也不允许LIKE other_type语法。您必须拼出复合类型的所有列(属性)。喜欢:

CREATE TYPE meeting_plus AS (
   id numeric
 , start date
 , "end" date
 , description text
 , total numeric
 , hours numeric
);

然后你可以使用:

RETURNS SETOF meeting_plus

就像你想要的那样。

但是对于一个函数,我会RETURNS TABLE()改用并拼出返回类型:

RETURNS TABLE (
   id numeric
 , start date
 , "end" date
 , description text
 , total numeric
 , hours numeric)

哦,我不会在 Postgres 中使用“开始”和“结束”作为标识符。两者都是标准 SQL 中的保留字。"end" 在 Postgres 中是绝对保留的,并且必须始终用双引号引起来。

于 2021-09-05T22:07:44.423 回答