用for循环打开隐式游标

时间:2012-11-16 09:21:44

标签: plsql oracle11g

我有一个存储过程,其中包含以下pl / sql块。这个块在for语句中使用select查询,但我需要将该静态变量更改为动态查询。当我改变它有错误。有没有办法在隐式游标中使用带有FOR LOOP的变量。

  declare
      sql_query varchar2(32767) := 'select ctlchar ';
      kpiNameQuery varchar2(600);
      isWg boolean := true;
    begin
          IF isWG then
             kpiNameQuery := 'select distinct KPI_NAME from weeklykpi where kpi_name in (select kpi_wg from auxillary.kpi_types) order by 1';

      Else
        kpiNameQuery := 'select distinct KPI_NAME from weeklykpi where kpi_name in (select kpi_wg1 from auxillary.kpi_types) order by 1';
      End IF;         

     for KPI_NAME in kpiNameQuery
      loop
          sql_query := sql_query || ' , min(case when KPI_NAME = '''||x.KPI_NAME||''' then KPI_VALUE end) as '||x.KPI_NAME;
          dbms_output.put_line(sql_query);
      end loop;
end;

2 个答案:

答案 0 :(得分:1)

不幸的是,the doc states

  

如果动态SQL语句是返回多行的SELECT语句,则本机动态SQL会为您提供以下选项:

     
      
  • 将EXECUTE IMMEDIATE语句与BULK COLLECT INTO子句一起使用。
  •   
  • 使用OPEN FOR,FETCH和CLOSE语句。
  •   

所以你必须使用REF游标(或EXECUTE IMMEDIATE并循环结果)。

顺便提一下,在您的情况下,您可以选择静态SQL并具有相似的性能:

BEGIN
   FOR cc IN (SELECT DISTINCT KPI_NAME
                FROM weeklykpi
               WHERE kpi_name IN (SELECT CASE WHEN l_variable = 1
                                                  THEN kpi_wg
                                              ELSE kpi_wg1
                                         END
                                    FROM auxillary.kpi_types) LOOP
               ORDER BY 1
      -- do something
   END LOOP;
END;

你必须使用除布尔之外的其他类型,因为SQL不知道。

答案 1 :(得分:1)

使用光标

可以实现以下类似功能
declare
      type t_cursor is ref cursor;
      c_cursor t_cursor;
      l_sql varchar2(512);
      l_var number;
   begin
     l_sql := 'select count(*) from emp';  -- do dynamic check before here for    
   -- correct sql
     open c_cursor for l_sql;
     loop
       fetch c_cursor 
        into l_var;           
       exit When c_cursor%notfound;
       DBMS_OUTPUT.put_line ('val '||l_var);           
     end loop;  
     close c_cursor;
  end;