将公式存储在表中并将其用于将来的计算

时间:2014-08-13 10:19:58

标签: database postgresql

我需要将公式存储到表中(用户必须管理这些公式)并使用它来计算,使用数据库的信息,一些字段并存储它们。公式随时间而变化,没有常数变量。

公式可以是:

(a*b+c)/24.5

2456.789*a+b²-c+23.58*d

我使用PostgreSQL作为数据库系统。我该如何正确实现?

1 个答案:

答案 0 :(得分:1)

如果公式是有效的SQL表达式,那么你可以使用PL / PgSQL和EXECUTE来运行它们......但这样做是非常不安全的,因为用户可以调用任意SQL函数。

如果它们不是有效的SQL表达式,那么您必须确定它们的内容,并使用适当的表达式处理器。

因此,在有效地回答这个问题之前,您需要定义公式可以做什么和不能做什么,用户的信任程度等等。

示例:使用Python和SymPy

我只想要纯粹的表达,我可能会使用SymPy和PL / Pythonu,但我不喜欢缺少沙盒版本。 e.g:

yum install sympy

(或您首选的apt-get等效物)然后

CREATE OR REPLACE FUNCTION eval_user_expr(userexpr text) 
RETURNS float8 
LANGUAGE plpythonu
AS $$
from sympy.parsing.sympy_parser import parse_expr
return float(parse_expr(userexpr));
$$;

或者如果你想把变量作为输入:

CREATE OR REPLACE FUNCTION eval_user_expr(userexpr text,  varnames text[], varvalues float8[]) 
RETURNS float8 
LANGUAGE plpythonu
AS $$
from sympy.parsing.sympy_parser import parse_expr
return float(parse_expr(userexpr, dict(zip(varnames, varvalues))));

然后使用:

regress=# SELECT eval_user_expr('2456.789*a+b**2-c+23.58*d', ARRAY['a', 'b', 'c', 'd'], ARRAY[3, 4, 9, 42]);
 eval_user_expr 
----------------
       8367.727
(1 row)

当然,这非常笨拙。它将所有值都视为双精度浮点(Python' s float是双精度值)。我没有看到一个简单的解决方案,因为Python的hetrogenous-typed dict没有匹配的原生PostgreSQL类型。你可以通过json或类似的,但它仍然非常有限。

这还要求您使用SymPy的表达式语法。例如,无法理解:

regress=# SELECT eval_user_expr('b²', ARRAY['b'], ARRAY[1]);
ERROR:  SyntaxError: invalid syntax (<string>, line 1)
CONTEXT:  Traceback (most recent call last):
  PL/Python function "eval_user_expr", line 3, in <module>
    return float(parse_expr(userexpr, dict(zip(varnames, varvalues))));
  PL/Python function "eval_user_expr", line 756, in parse_expr
  PL/Python function "eval_user_expr", line 690, in eval_expr
PL/Python function "eval_user_expr"

并且您必须使用Python表单b**2

regress=# SELECT eval_user_expr('b**2', ARRAY['b'], ARRAY[1]);
 eval_user_expr 
----------------
              1
(1 row)

其他选项

PL / Lua,依靠它的沙箱并直接运行Lua表达式。

使用现有表达式解析和执行库的自定义C扩展(如果可以找到一个好的扩展)。也许GNU libmatheval(我从未尝试过或测试过它)。

PL / perl如果你能找到合适的Perl表达式解析库。或PL / V8,如果你能找到一个JavaScript。或者您愿意运行pl/perl沙盒并运行用户提供的原始Perl表达式。

PL / Java,如果您非常绝望,可以找到满足您Java需求的东西。