准备
您的公式如下所示:
d*b+(l*4+r)+(i/d)+s
我将用$n
符号替换变量,以便可以直接在plpgsql中将其替换为值EXECUTE
(请参见下文):
$1*$5+($3*4+$2)+($6/$1)+$4
您可以额外存储原始公式(供人眼使用),也可以使用以下表达式动态生成此格式:
SELECT regexp_replace(regexp_replace(regexp_replace(
regexp_replace(regexp_replace(regexp_replace(
'd*b+(l*4+r)+(i/d)+s'
, '\md\M', '$1', 'g')
, '\mr\M', '$2', 'g')
, '\ml\M', '$3', 'g')
, '\ms\M', '$4', 'g')
, '\mb\M', '$5', 'g')
, '\mi\M', '$6', 'g');
只要确保您的翻译是正确的即可。regexp表达式的一些解释:
\ m ..仅在单词开头
匹配\ M ..仅在单词结尾匹配
第四个参数'g'
..全局替换
核心功能
CREATE OR REPLACE FUNCTION f_calc(
d int -- days worked that month
,r int -- new nodes accuired
,l int -- loyalty score
,s numeric -- subagent commission
,b numeric -- base rate
,i numeric -- revenue gained
,formula text
,OUT result numeric
) RETURNS numeric AS
$func$
BEGIN
EXECUTE 'SELECT '|| formula
INTO result
USING $1, $2, $3, $4, $5, $6;
END
$func$ LANGUAGE plpgsql SECURITY DEFINER IMMUTABLE;
呼叫:
SELECT f_calc(1, 2, 3, 4.1, 5.2, 6.3, '$1*$5+($3*4+$2)+($6/$1)+$4');
返回值:
29.6000000000000000
要点
该功能以6值参数formula text
为第7位。我将公式放在最后,因此我们可以使用$1 .. $6
代替$2 .. $7
。仅出于可读性考虑。
我认为合适的是为值分配了数据类型。分配适当的类型(以执行基本的健全性检查)或将其全部设置为numeric
:
通过USING
子句传递用于动态执行的值。这样可以避免来回转换,并使一切变得更简单,更安全,更快。
我使用一个OUT
参数是因为它更优雅,并且语法更短。RETURN
不需要final ,将自动返回OUT参数的值。
考虑@Chris 撰写的有关安全性的讲座以及手册中的“安全地编写安全定义函数”一章。在我的设计中,注射点是配方本身。
您可以对某些参数使用默认值,以进一步简化调用。