扩展现有的 PostgreSQL 类型

Extend existing PostgreSQL type

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

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

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

因为我有一个函数 returns 来自 meetings table 的所有列,然后是另外两个 totalhours 列在查询时计算。该函数如下所示:

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 列的 table 不同 两个新的 hourstotal 列。我想要做的是这样的事情(显然下面的语法实际上并不存在......但我不确定是否有另一种方法可以使用类似的 shorthand 语法来做到这一点):

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)

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

关于你的核心问题

Is it possible to extend an existing datatype?

,不可能。不在 CREATE FUNCTIONRETURNS 子句中,不在 PostgreSQL 版本 14 之前的任何其他地方。

您可以 return 一个复合类型的字段,加上任何类型的附加字段。但这有细微的不同:

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

调用该函数:

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

Returns 作为 return 列之一的嵌套复合类型,例如:

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

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

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

但我不会去那里。

My current workaround is to create a view and then have that function simply query that view and return the view's type.

那就用视图吧。不要在它之上创建附加功能。结案。

如果你实际上是想说:

... then use the row type of the view in the RETURNS clause of the function

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

RETURNS TABLE (LIKE meeting_instances)

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

RETURNS SETOF meeting_instances

(LIKE some_table)CREATE TABLE 的记录语法。 CREATE FUNCTIONRETURNS 子句目前支持相同,但没有文档,所以不要使用它。

回到创建 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() 并拼出 return 类型:

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

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