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

时间:2015-07-04 19:46:16

标签: postgresql plpgsql code-reuse postgresql-9.4

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

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

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

1 个答案:

答案 0 :(得分:2)

这个问题非常有趣,因为它反映了自定义聚合函数的非标准使用。

  

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

我们需要:

  • 作为聚合的自定义复合类型对特定类型的值进行操作
  • 状态转换函数,用于在临时表中保存连续的行,
  • 最终函数,执行计算并返回最终结果。
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