PostgreSQL:将列中的函数存储为值

Pet*_*ter 2 postgresql dynamic-sql

函数可以作为匿名函数直接存储在列中作为其值吗?

假设我想将此函数存储在列中.示例(伪代码):

表my_table:pk(int),my_function(func)

func(x){return x*100}

后来用它作为:

select 
    t.my_function(some_input) AS output
from 
    my_table as t 
where t.pk = 1999
Run Code Online (Sandbox Code Playgroud)

每个pk的功能可能不同.

Erw*_*ter 6

你的标题问的不是你的例子.

  1. 必须先创建一个函数才能调用它.(标题)
  2. 表达式必须被评估.你需要一个元功能.(例)

我将为两者提供解决方案.

1.动态评估表达式

您必须考虑到结果类型可能会有所不同.我使用多态类型.

-- DROP SCHEMA x CASCADE;
CREATE SCHEMA x;

CREATE OR REPLACE FUNCTION x.f1(int)
  RETURNS int AS
$$SELECT $1 * 100;$$
  LANGUAGE sql IMMUTABLE;

CREATE OR REPLACE FUNCTION x.f2(text)
  RETURNS text AS
$$SELECT $1 || '_foo';$$
  LANGUAGE sql IMMUTABLE;

CREATE TABLE x.my_expr (expr text PRIMARY KEY, def text, rettype text);

INSERT INTO x.my_expr VALUES
 ('x', $$x.f1(3)$$, 'int')
,('y', $$x.f2('bar')$$, 'text')
;

CREATE OR REPLACE FUNCTION x.f_eval(text, _type anyelement, OUT _result anyelement)
  AS
$x$
BEGIN

EXECUTE
'SELECT ' || (SELECT def FROM x.my_expr WHERE expr = $1)
INTO _result;

END;
$x$
LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

呼叫:

SELECT x.f_eval('x', (SELECT rettype FROM x.my_expr WHERE expr = 'x'));
 f_eval
--------
 300
(1 row)

SELECT x.f_eval('y', (SELECT rettype FROM x.my_expr WHERE expr = 'y'));
 f_eval
---------
 bar_foo
(1 Zeile)
Run Code Online (Sandbox Code Playgroud)

2.动态创建和使用函数

可以动态创建函数然后使用它们.但是,您无法使用纯SQL执行此操作.您必须使用另一个函数来执行此操作,或者至少使用PostgreSQL 9.0中引入的匿名代码块(DO语句).

它可以像这样工作:

-- DROP SCHEMA x CASCADE;
CREATE SCHEMA x;
CREATE TABLE x.my_func (func text PRIMARY KEY, def text);

INSERT INTO x.my_func VALUES('f'
, $$CREATE OR REPLACE FUNCTION f(int)
  RETURNS int AS
'SELECT $1 * 100;'
  LANGUAGE sql IMMUTABLE$$);

CREATE OR REPLACE FUNCTION x.f_create_func(text)
RETURNS void AS $x$
BEGIN

EXECUTE (SELECT def FROM x.my_func WHERE func = $1);

END;
$x$
LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

呼叫:

select x.f_create_func('f');
SELECT f(3);
Run Code Online (Sandbox Code Playgroud)

您可能希望之后删除该功能.

在大多数情况下,您应该只创建函数并完成它.如果您遇到多个版本或特权的问题,请使用单独的模式.

有关我在此处使用的功能的更多信息,请参阅dba.stackexchange.com上的相关答案.