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

时间:2011-11-09 16:44:08

标签: 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

每个pk的功能可能会有所不同。

1 个答案:

答案 0 :(得分:6)

你的标题除了你的例子之外还有别的东西。

  1. 功能必须创建才能调用它。 (标题)
  2. 必须评估表达式。你需要一个元功能。 (实施例)
  3. 我将为两者提供解决方案。

    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;
    

    呼叫:

    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)
    

    2。动态创建和使用函数

    可以动态创建函数然后使用它们。但是,您无法使用纯SQL执行此操作。您必须使用另一个function来执行此操作,或至少使用PostgreSQL 9.0中引入的anonymous code block (DO statement)

    它可以像这样工作:

    -- 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;
    

    呼叫:

    select x.f_create_func('f');
    SELECT f(3);
    

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

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

    有关我在此处使用的功能的详细信息,请参阅my related answer on dba.stackexchange.com