我有一些表格,每年都包含相同类型的数据,但是收集的数据略有不同,因为它们可能没有相同的字段。
d_abc_2016
d_def_2016
d_ghi_2016
d_jkl_2016
每个表都有一些常量:
company_id
, employee_id
, salary
。然而,每个表可能有或可能没有用于计算总激励的这些字段:
bonus
, commission
, cash_incentives
。还有很多其他字段,但这里只是举例。numeric
值得注意的是,用户只能运行SELECT
语句。我想要做的是:
- 给用户调用
SELECT
并指定自己的字段的能力 - 将正在使用的表名传递到函数中以使用条件逻辑来确定查询字符串应如何构建为最终的
total_incentives
计算,同时传递整个表格,以便不必传递大量参数到函数中
SELECT employee_id, salary, total_incentives(t, 'd_abc_2016')
FROM d_abc_2016 t;
所以被调用的函数将计算该员工的数字奖励
total_incentives
,并显示他们的工资salary
。但用户可能会选择添加其他字段进行查看。对于该函数,由于在
total_incentives
函数中使用的字段会因表而异,因此我需要创建逻辑来动态构建查询字符串。CREATE OR REPLACE FUNCTION total_incentives(ANYELEMENT, t text)
RETURNS numeric AS
$$
DECLARE
-- table name lower case in case user typed wrong
tbl varchar(255) := lower($2;
-- parse out the table code to use in conditional logic
tbl_code varchar(255) := split_part(survey, '_', 2);
-- the starting point if the query string
base_calc varchar(255) := 'salary + '
-- query string
query_string varchar(255);
-- have to declare this to put computation INTO
total_incentives_calc numeric;
BEGIN
IF tbl_code = 'abc' THEN
query_string := base_calc || 'bonus';
ELSIF tbl_code = 'def' THEN
query_string := base_calc || 'bonus + commission';
ELSIF tbl_code = 'ghi' THEN
-- etc...
END IF;
EXECUTE format('SELECT $1 FROM %I', tbl)
INTO total_incentives_calc
USING query_string;
RETURN total_incentives_calc;
END;
$$
LANGUAGE plpgsql;
这将导致一个:
ERROR: invalid input syntax for type numeric: "salary + bonus"
CONTEXT: PL/pgSQL function total_incentives(anyelement,text) line 16 at EXECUTE
由于它应该返回一组“numeric”值,因此请更改为以下内容:
CREATE OR REPLACE FUNCTION total_incentives(ANYELEMENT, t text)
RETURNS SETOF numeric AS
$$
...
RETURN;
我得到了相同的错误。
看来可能是它试图返回一个表格。
CREATE OR REPLACE FUNCTION total_incentives(ANYELEMENT, t text)
RETURNS TABLE(tot_inc numeric) AS
$$
...
出现了相同的错误。
实际上,任何变化都会产生这个结果。所以真的不确定如何使其工作。
查看RESULT QUERY
、RESULT NEXT
或RESULT QUERY EXECUTE
。
https://www.postgresql.org/docs/9.6/static/plpgsql-control-structures.html
RESULT QUERY
不起作用,因为它似乎采用硬编码查询,不会接受变量。
RESULT NEXT
迭代每个记录,我认为这对我的需求不合适,而且似乎会非常慢...并且从我所看到的内容来看,它采用了硬编码查询。
RESULT QUERY EXECUTE
听起来很有前途。
-- EXECUTE format('SELECT $1 FROM %I', tbl)
-- INTO total_incentives_calc
-- USING query_string;
RETURN QUERY
EXECUTE format('SELECT $1 FROM %I', tbl)
USING query_string;
并获得:
ERROR: structure of query does not match function result type
DETAIL: Returned type character varying does not match expected type numeric in column 1.
CONTEXT: PL/pgSQL function total_incentives(anyelement,text) line 20 at RETURN QUERY
它应该返回数字
。
最后,我可以让它工作,但这不是DRY。我不想为每个表格创建一堆重复的代码的单独函数。我看到的大多数有效示例在函数中有整个查询,并像以下方式调用:
SELECT total_incentives(d_abc_2016, 'd_abc_2016');
所以任何额外的列都必须在函数中指定为:
EXECUTE format('SELECT employee_id...)
考虑到用户只能在查询中运行SELECT
,这真的不是一个选择。他们需要在查询中指定想要查看的任何其他列。
我发布了类似的问题,但被告知不清楚,希望这个更详细的版本能更清楚地解释我正在尝试做什么。