如何执行存储在 table 的另一列中的(涉及相同 table 的列的表达式)?

How to execute an (expression involving columns of the same table) stored in another column of the table?

我的 table 看起来像这样-

id     | expression                           | unit_cost | demand |total_cost|
------ | -------------------------------------| ----------|--------|----------|
1      | (unit_cost*4)*demand                 | 5         |100     |          |
2      | (unit_cost*(8/100)demand)*demand     | 10        |50      |          |

现在,我想根据表达式列使用表达式中指定的其他列来计算 total_cost。可以更改架构,这只是一个示例,展示了我真正想做的事情。

注意:每一行的表达式都会不同

您可以使用这样的函数:

create or replace function eval(p_row the_table) 
  returns integer
as
$body$
declare
  l_result integer;
  l_sql text;
begin

  l_sql := format('select %s from (values (, ) ) as t(unit_cost, demand)', 
                   p_row.expression);

  execute l_sql
    into l_result
    using p_row.unit_cost, p_row.demand;

  return l_result;
end;
$body$
language plpgsql;

(您需要将 the_table 替换为您的 table 的实际名称)

我决定将 table 的完整行作为参数传递,这样如果您决定在 table 中使用更多列,则无需更改任何内容表达式。

生成的 SQL 看起来像这样(例如第一行):

select (unit_cost*4)*demand 
from ( values (, )) as t(unit_cost, demand);

values 子句中的参数然后与 using ... 部分一起传递,以确保它们被正确的数据类型处理,这意味着它被执行为:

select (unit_cost*4)*demand 
from ( values (5, 100)) as t(unit_cost, demand);

你可以这样使用它:

select t.id, t.unit_cost, t.demand, eval(t) as total_cost
from the_table t;

注意用于将行传递给函数的 table 别名。


如果你知道输入值永远不会改变,你也可以直接传递它们:

create or replace function eval(p_expression text, p_demand int, p_unit_cost int)
   returns integer
as
$body$
declare
  l_result integer;
  l_sql text;
begin

  l_sql := format('select %s from (values (, ) ) as t(unit_cost, demand)',
                  p_expression);

  execute l_sql
    into l_result
    using p_unit_cost, p_demand;
  return l_result;
end;
$body$
language plpgsql;

然后这样称呼它:

select id, unit_cost, demand, eval(t.expression, t.demand, t.unit_cost) as total_cost
from the_table t;

第一个版本(传递完整的行)的优点是永远不会混淆参数的顺序而意外地将需求作为单位成本传递。

Online example