PL / pgSQL代码的问题

时间:2014-07-08 21:17:39

标签: function postgresql cursor plpgsql dynamic-sql

我对plpgsql不是很有经验,所以我在这里有2个问题。

  1. Postgres是否可以按照我们在plsql的动态sql中使用游标的方式使用游标?基本上我不想在plsql中使用过程,所以我创建了一个光标,它将保存我的动态查询的输出,然后我在另一个查询中的循环中使用该值,以使我的输出显示在屏幕上。我正在尝试与Postgres一样但不能这样做。
  2. 是否有可能在这种情况下避免创建永久性功能来实现这一目标?
  3. 这是我运行正常的oracle脚本:

    DECLARE
      CURSOR cur_tables IS
         SELECT  NAME,
    'SELECT PROPERTY_VALUE FROM '
             || USERNAME
             || '.P_PROPERTY WHERE PROPERTY_NAME = ''VERSION'''
                     AS dsql
           FROM CB_DATASOURCE
          WHERE (UPPER(USERNAME) LIKE 'NAV_PS_%' or UPPER(USERNAME) LIKE 'CBPS_%' or UPPER(USERNAME) LIKE 'DEFAULTPS');
      CURR_VERSION VARCHAR2(1000);
    BEGIN
      FOR r_tables IN cur_tables LOOP
       begin
         EXECUTE IMMEDIATE r_tables.dsql INTO CURR_VERSION;
         DBMS_OUTPUT.put_line(r_tables.NAME || ': ' || CURR_VERSION);
        exception
         when others then
          DBMS_OUTPUT.put_line(r_tables.NAME || ' no table');
       end;   
      END LOOP;
    END;
    /
    

    这是我的postgres函数,我无法使其工作但最终想避免使用永久函数

    create or replace function upgrade_version() returns setof record as $$ 
    declare
     r record;
     loopy record;
     isql text;
     CURR_VERSION text;
    begin
     for r in SELECT 'SELECT PROPERTY_VALUE FROM '
             || USERNAME
             || '.P_PROPERTY WHERE PROPERTY_NAME = ''VERSION'''
                     AS dsql
           FROM CB_DATASOURCE
          WHERE (UPPER(USERNAME) LIKE 'NAV_PS_%' or UPPER(USERNAME) LIKE 'CBPS_%' or UPPER(USERNAME) LIKE 'DEFAULTPS') loop
      isql := r.dsql;
      EXECUTE isql INTO CURR_VERSION;
      RETURN next loopy;
     end loop;
     return;
    end;
    $$ language 'plpgsql';
    

    我真的很感激这方面的任何意见。

2 个答案:

答案 0 :(得分:4)

您似乎在尝试使用DO statement

DO
$do$ 
DECLARE
   r record;
   curr_version text;
BEGIN
   FOR r IN 
      SELECT name, format($$
         SELECT property_value
         FROM   %I.p_property
         WHERE  property_name = 'VERSION'$$, username) AS dsql
      FROM   cb_datasource
      WHERE  upper(username) LIKE ANY ('{NAV_PS_%, CBPS_%, DEFAULTPS}')
   LOOP
      BEGIN
         EXECUTE r.dsql INTO curr_version;
         RAISE NOTICE '%: %', r.name, curr_version;
      EXCEPTION WHEN OTHERS THEN
         RAISE NOTICE '%: no table', r.name;
      END;   
   END LOOP;
END
$do$

重点

  • RETURN声明无法DO,但您可以RAISE通知等。 从eventually would like to refrain from using a permanent function开始,似乎对你来说是完美的 请注意,DO语句的默认过程语言仍为plpgsql

  • 在Postgres中,不带引号的标识符被转换为小写(而不是Oracle,它们是大写的)。

  • 要捕获循环中的异常,您需要将主体包装在单独的块中。 Read the manual here.

  • 您需要清理动态生成的SQL字符串中的标识符,以免易受SQL注入和非标准名称的其他问题的影响。您的Oracle代码也缺乏。
    我将format()%I用于此目的。更多信息:
    How to use EXECUTE FORMAT ... USING in postgres function

  • 使用ANY

  • 缩短WHERE条款
  • 您知道_LIKE模式中的占位符吗?对于文字_,请将其转义:\_

答案 1 :(得分:3)

您可以使用DO $$ $$脚本避免创建永久功能:http://www.postgresql.org/docs/9.3/static/sql-do.html

但是,我不清楚你是如何完全避免使用PL / pgSQL代码的,因为你根据另一个查询的内容定义了一个游标。您在Oracle中使用PL / SQL代码;为什么你不需要PostgreSQL中的程序代码?

如果您偏好游标,您当然可以在PL / pgSQL函数中使用OPEN CURSOR FOR EXECUTE,但是您不能使用与Oracle相同的结构;在PL / pgSQL中,您不能将游标作为字符串替换进行DECLARE。这只是在OPEN期间完成的:http://www.postgresql.org/docs/9.3/static/plpgsql-cursors.html

除了认为每个用户都有一个EAV设置表并不是一个很棒的设计......