PostgreSQL:重用适用于虚拟表数据的函数代码

Posted

技术标签:

【中文标题】PostgreSQL:重用适用于虚拟表数据的函数代码【英文标题】:PostgreSQL: Reuse function code that works on virtual table data 【发布时间】:2015-07-04 19:46:15 【问题描述】:

我的代码适用于 3 列 (id | timestamp | value) 的数据集(= 多行)并产生单个数值结果(分数)。

现在我想把这段代码放在一个函数中,以便我可以重用它。假设我有 4 个其他查询都生成具有这 3 个列的数据集,我想从中计算 score,而无需复制/粘贴我的代码......我该怎么做?似乎无法将 TABLE(...) 类型作为函数参数传递。

我认为我不能使用聚合函数,因为我的评分代码会在内部添加新行、对它们进行分组等等。我需要同时处理所有行并且没有状态转换。

【问题讨论】:

什么是“虚拟表”?你的意思是一个表函数(“设置返回函数”)?请显示您的功能代码(或简化示例)并详细说明want to reuse my scoring code。您需要更具体地说明您想要做什么。 Postgres 没有表变量,还有其他方法... 编辑问题,而不是将太多重要信息放入 cmets。不是那个地方。 那么请给我们看一下你的函数代码 那么当你说“代码适用于数据集”时,你指的是哪个代码?那个代码在哪里?它现在在做什么? 如果您不显示要通过动态输入重用的代码,我们将无法帮助您。如果您的函数过于复杂,请提供一个简化示例来展示基本原理。听起来你需要dynamic SQL。 【参考方案1】:

这个问题很有趣,因为它引发了对自定义聚合函数的非标准使用的反思。

(...) 想象一些查询首先按 id 对行进行排序,然后相乘 第一个 row.value 的值为 4th,并将其设置为新的 第一行的值。然后它返回第一个

我们需要:

作为聚合的自定义复合类型对特定类型的值进行操作, 状态转换函数,将连续行保存在临时表中, final 函数,执行计算并返回最终结果。
create type scores as (id int, val numeric);

create function save_scores(p scores, n scores)
returns scores language plpgsql as $$
begin
    if p is null then 
        create temp table temp_scores of scores;
    end if;
    insert into temp_scores values (n.id, n.val);
    return n;
end $$;

create function calculate_scores(t scores)
returns numeric language plpgsql as $$
declare
    id1 int;
    val4 numeric;
    res numeric;
begin
    select id into id1 from temp_scores order by id limit 1;
    select val into val4 from temp_scores order by id offset 3 limit 1;
    update temp_scores set val = val* val4 where id = id1;
    select val into res from temp_scores where val < 5 order by id limit 1;
    drop table temp_scores;
    return res;
end $$;

聚合:

create aggregate get_scores(scores) (
    sfunc = save_scores,
    finalfunc = calculate_scores,
    stype = scores
);

还有一些检查:

select get_scores(row)
from (
    values (4, 3.1), (3, 1.2), (2, 5.2), (1, 2)
    ) row
-- gives 1.2

select get_scores(row)
from (
    values (4, 3.1), (3, 1.2), (2, 5.2), (1, 1)
    ) row
-- gives 3.1

由于使用了临时表,聚合只能在单个查询中使用一次。为简单起见,省略列 timestamp

【讨论】:

我的问题是我的函数需要处理多行的数据集。我按问题编辑以使其更清楚。 使用简单的功能是不可能的。您必须创建一个聚合。 哇!我确实读过它。你所写的关于聚合函数的内容是不正确的。这是唯一的解决方案,并不难。当然,如果我理解正确的话,你的目标是什么。 抱歉,您只是写了“创建聚合”,没有任何进一步的评论。这听起来好像你没有读过这个问题。 ;) 谢谢你的回答 - 有趣。我不明白临时表的性能影响。我可能每秒执行超过 100 个请求 - 我认为临时表仍会写入磁盘? 没关系。临时表在内存中处理(除非发生溢出)。但是,这种解决方案似乎并不是特别有效。

以上是关于PostgreSQL:重用适用于虚拟表数据的函数代码的主要内容,如果未能解决你的问题,请参考以下文章

Postgresql:适用于(时间戳,字符串)的多列索引

如何在 Postgresql 中获取结合 old.variablename 的列数据?

postgreSQL 选择聚合函数中未使用的附加列

列出引用 PostgreSQL 中表的存储函数

在 PostgreSQL 中重用存储过程的结果

PostgreSQL 约束