Preparar
Suas fórmulas são assim:
d*b+(l*4+r)+(i/d)+s
Eu substituiria as variáveis pela $n
notação para que elas possam ser substituídas pelos valores diretamente no plpgsql EXECUTE
(veja abaixo):
$1*$5+($3*4+$2)+($6/$1)+$4
Você pode armazenar suas fórmulas originais adicionalmente (para o olho humano) ou gerar esse formulário dinamicamente com uma expressão como:
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');
Apenas certifique-se de que sua tradução é sólida. Alguma explicação para as expressões regexp :
\ m .. corresponde apenas ao início de uma palavra
\ M .. corresponde apenas ao final de uma palavra
Quarto parâmetro 'g'
.. substituir globalmente
Função principal
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;
Ligar:
SELECT f_calc(1, 2, 3, 4.1, 5.2, 6.3, '$1*$5+($3*4+$2)+($6/$1)+$4');
Devoluções:
29.6000000000000000
Pontos principais
A função assume o parâmetro 6 value e formula text
como 7th. Coloquei a fórmula por último, para que possamos usar em $1 .. $6
vez de $2 .. $7
. Apenas por uma questão de legibilidade.
Atribuí tipos de dados para os valores como achar melhor. Atribua tipos adequados (para implementar verificações básicas de sanidade) ou apenas faça todos eles numeric
:
Passe valores para execução dinâmica com a USING
cláusula Isso evita a transmissão para frente e para trás e torna tudo mais simples, seguro e rápido.
Eu uso um OUT
parâmetro porque é mais elegante e cria uma sintaxe mais clara e clara. Uma final RETURN
não é necessária, o valor do (s) parâmetro (s) OUT é retornado automaticamente.
Considere a palestra sobre segurança de @Chris e o capítulo "Como escrever com segurança as funções do DEFINER DE SEGURANÇA" no manual. Na minha concepção, o único ponto de injeção é a própria fórmula.
Você pode usar padrões para alguns parâmetros para simplificar ainda mais a chamada.