扩展现有的 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 的所有列,然后是另外两个 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
列的 table 不同 和 两个新的 hours
和 total
列。我想要做的是这样的事情(显然下面的语法实际上并不存在......但我不确定是否有另一种方法可以使用类似的 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 FUNCTION
的 RETURNS
子句中,不在 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 FUNCTION
的 RETURNS
子句目前支持相同,但没有文档,所以不要使用它。
回到创建 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 中绝对保留,必须始终用双引号引起来。
是否可以扩展 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 的所有列,然后是另外两个 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
列的 table 不同 和 两个新的 hours
和 total
列。我想要做的是这样的事情(显然下面的语法实际上并不存在......但我不确定是否有另一种方法可以使用类似的 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 FUNCTION
的 RETURNS
子句中,不在 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 FUNCTION
的 RETURNS
子句目前支持相同,但没有文档,所以不要使用它。
回到创建 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 中绝对保留,必须始终用双引号引起来。