【问题标题】:PostgreSQL syntax error when using EXECUTE in Function在函数中使用 EXECUTE 时 PostgreSQL 语法错误
【发布时间】:2011-10-15 05:43:35
【问题描述】:

我正在尝试创建一个引用 PostgreSQL 8.4 中的临时表的函数。根据我的研究,似乎最好的方法是使用EXECUTE 命令从定义的字符串执行我的查询。

不幸的是,我在尝试创建函数时遇到了奇怪的语法错误。

我目前的函数定义如下:

CREATE OR REPLACE FUNCTION example() RETURNS void AS $$
  EXECUTE 'INSERT INTO table1 (col1, col2, col3) SELECT col1, col2, col3 from temp_table';
$$ LANGUAGE SQL;

我得到的错误是:

ERROR:  syntax error at or near "'INSERT INTO table1 (col1, col2, col3) SELECT col1, col2, col3 from temp_table'"
LINE 2:   execute 'INSERT INTO table1 (col1, col2, col3) SELECT col1...

无论字符串文字中的实际内容如何,​​我似乎都会遇到相同的错误。

我的问题是,1) 使用 EXECUTE 功能的正确语法是什么,以及 2) 是否有更好的方法来编写像这样引用临时表的函数?

【问题讨论】:

    标签: function postgresql syntax-error execute temp-tables


    【解决方案1】:

    我认为您的问题是您使用的语言。 SQL 语言中的EXECUTE

    EXECUTE 用于执行之前准备好的语句。由于准备好的语句仅在会话期间存在,因此准备好的语句必须是由在当前会话中较早执行的PREPARE 语句创建的。

    EXECUTE in PL/pgSQL不同:

    您通常希望在 PL/pgSQL 函数中生成动态命令,即每次执行时将涉及不同表或不同数据类型的命令。 PL/pgSQL 为命令缓存计划的正常尝试(如第 39.10.2 节所述)在这种情况下将不起作用。为了处理这类问题,提供了EXECUTE 语句:

    EXECUTE command-string [ INTO [STRICT] target ] [ USING expression [, ... ] ];
    

    当您想使用 PL/pgSQL EXECUTE(将字符串作为 SQL 执行)时,您正在使用 SQL EXECUTE(执行准备好的语句)。

    试试这个:

    CREATE OR REPLACE FUNCTION example() RETURNS void AS $$
    BEGIN
        EXECUTE 'INSERT INTO table1 (col1, col2, col3) SELECT col1, col2, col3 from temp_table';
    END;
    $$ LANGUAGE PLPGSQL;
    

    或者,另一个看起来更接近您似乎想要做的例子:

    create or replace function example(tname text) returns void as $$
    begin
        execute 'insert into ' || tname || ' (name) values(''pancakes'')';
    end;
    $$ language plpgsql;
    

    这会将'pancakes' 插入到您将tname 参数传递给函数的表中。

    【讨论】:

      【解决方案2】:

      EXECUTE 用于执行准备好的语句,只需要准备好的语句名称作为参数。

      如果您尝试执行一条 SQL 语句(如您的示例中所示),只需将其包含在函数体中即可。

      查看manual 了解有关“查询语言 (SQL) 函数”的更多信息。

      OTOH,如果您尝试创建 PL/pgSQL 函数(这不是您在问题中显示的内容),那么您需要将您的函数转换为 PL/pgSQL function

      【讨论】:

      • 我不能只在函数主体中包含查询,因为它引用了一个在创建函数时不存在的临时表。是使用 PL/pgSQL 函数的唯一方法吗?
      【解决方案3】:

      这是我测试的一个示例,我使用 EXECUTE 运行选择并将其结果放入游标中。

      1.创建表:

      create table people (
        nickname varchar(9),
        name varchar(12),
        second_name varchar(12),
        country varchar(30)
        );
      

      2。创建函数:

      CREATE OR REPLACE FUNCTION fun_find_people (col_name text, col_value varchar)
      RETURNS void AS
      $BODY$
      DECLARE
          local_cursor_p refcursor;
          row_from_people RECORD;
      
      BEGIN
          open local_cursor_p FOR
              EXECUTE 'select * from people where '|| col_name || ' LIKE ''' || col_value || '%'' ';
      
          raise notice 'col_name: %',col_name;
          raise notice 'col_value: %',col_value;
      
          LOOP
              FETCH local_cursor_p INTO row_from_people; EXIT WHEN NOT FOUND;
      
              raise notice 'row_from_people.nickname: %',  row_from_people.nickname ;
              raise notice 'row_from_people.name: %', row_from_people.name ;
              raise notice 'row_from_people.country: %', row_from_people.country;
          END LOOP;
      END;
      $BODY$ LANGUAGE 'plpgsql'
      

      3.运行函数 select fun_find_people('name', 'Cristian'); select fun_find_people('country', 'Chile');

      【讨论】:

        【解决方案4】:

        或者,您可以使用 DO 在匿名代码块中运行它。
        根据documentation(强调我的):

        DO 执行一个匿名代码块,或者换句话说,一个过程语言中的瞬态匿名函数。

        代码块被视为没有参数的函数体,返回 void。 它被解析并执行一次。


        这允许您运行通常无法运行的构造 SQL,而不会强制您构建一个函数来调用它:

        DO $$
        BEGIN
            execute 'ALTER DATABASE ' || current_database() || ' SET timezone TO ''UTC''';
            execute 'SET timezone TO ''UTC''';
        END;
        $$
        

        代替:

        CREATE OR REPLACE FUNCTION fix_database_timezone()
        RETURNS void AS
        $BODY$
        BEGIN
            execute 'ALTER DATABASE ' || current_database() || ' SET timezone TO ''UTC''';
            execute 'SET timezone TO ''UTC''';
        END;
        $BODY$ LANGUAGE 'plpgsql';
        
        fix_database_timezone();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-12-13
          • 2017-12-11
          • 1970-01-01
          • 2016-04-04
          • 1970-01-01
          • 1970-01-01
          • 2021-06-20
          • 1970-01-01
          相关资源
          最近更新 更多