【问题标题】:EXECUTE IMMEDIATE in plsql在plsql中立即执行
【发布时间】:2011-06-15 18:10:42
【问题描述】:

如何从这段代码中得到结果

EXECUTE IMMEDIATE 'SELECT * FROM ' || table_name

通过for循环

通常的方法是这样的

for items in (select * from this_table)
loop
htp.p(items.id);
end loop;

【问题讨论】:

    标签: sql oracle plsql cursor dynamic-sql


    【解决方案1】:

    如果你真的需要select * from动态表名,那么我可能会选择dbms_sql

    记录的类型

    create type tq84_varchar2_tab as table of varchar2(4000);
    /
    

    结果集的类型(记录的数组):

    create type tq84_varchar2_tab_tab as table of tq84_varchar2_tab;
    /
    

    执行选择并返回结果集实例的函数

    create or replace function tq84_select_star_from_table(table_name in varchar2) 
        return tq84_varchar2_tab_tab
    as
        stmt_txt     varchar2(4000);
        cur          number;
        columns_desc dbms_sql.desc_tab;
        column_cnt   number;
    
        result_set   tq84_varchar2_tab_tab;
    
    begin
    
        stmt_txt := 'select * from ' || table_name;    
    
        cur := dbms_sql.open_cursor;
    
        dbms_sql.parse(cur, stmt_txt, dbms_sql.native);
        dbms_sql.describe_columns(cur, column_cnt, columns_desc);
        dbms_sql.close_cursor(cur);
    
    
        stmt_txt := 'select tq84_varchar2_tab(';
    
        for i in 1 .. column_cnt loop 
    
            if i != 1 then
               stmt_txt := stmt_txt || ',';
            end if;
    
            stmt_txt := stmt_txt || columns_desc(i).col_name;
    
        end loop;
    
        stmt_txt := stmt_txt || ') from ' || table_name;
    
    --  dbms_output.put_line(stmt_txt);
    
        execute immediate stmt_txt 
        bulk collect into result_set;
    
        return result_set;
    
    
    end tq84_select_star_from_table;
    

    然后该函数可以与以下内容一起使用:

    declare
      records   tq84_varchar2_tab_tab;
    begin
    
      records := tq84_select_star_from_table('user_objects');
    
      for i in 1 .. records.count loop
          dbms_output.put_line (records(i)(5) || ': ' || records(i)(1));
      end loop;
    
    end;
    /
    

    【讨论】:

    • INTO 列表中的表达式“RESULT_SET”类型错误
    【解决方案2】:

    这是一个简单的函数,它使用传递的表名参数动态打开游标变量。

    create or replace function get_details_by_dno
        ( p_tab in user_tables.table_name%type
          , p_dno in dept.deptno%type )
        return sys_refcursor
    is
        rv sys_refcursor;
        stmt varchar2(32767);
    begin
        stmt := 'select * from '
            ||p_tab
            ||' where deptno = :1';
        open rv for stmt using p_dno;
        return rv;
    end;
    /
    

    它还使用 DEPTNO 作为过滤器;因此,如果我们传递一个没有这样列的表,函数将失败

    某些客户端可以解释引用光标的元数据。例如 JDBC 和 ODBC ResultSets 可以做到这一点。 SQL*Plus 可以做到:

    SQL> exec :rc := get_details_by_dno('DEPT', 50)
    
    PL/SQL procedure successfully completed.
    
    SQL> print rc
    
        DEPTNO DNAME          LOC           REGION
    ---------- -------------- ------------- ----------
            50 HOUSEKEEPING   INTERNAL
    
    SQL> exec :rc := get_details_by_dno('EMP', 50)
    
    PL/SQL procedure successfully completed.
    
    SQL> exec :rc := get_details_by_dno('EMP', 50)
    
    PL/SQL procedure successfully completed.
    
    SQL> print rc
    
         EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
    ---------- ---------- --------- ---------- --------- ---------- ---------- ----------
          8085 TRICHLER   PLUMBER         8061 08-APR-10       3500                    50
          8060 VERREYNNE  PLUMBER         8061 08-APR-08       4000                    50
          8061 FEUERSTEIN PLUMBER         7839 27-FEB-10       4500                    50
          8100 PODER      PLUMBER         8061                 3750                    50
    
    SQL>
    

    PL/SQL 无法做到这一点。所以我们需要明确表名和列名。

    create or replace procedure print_details_by_dno
        ( p_tab in user_tables.table_name%type
          , p_dno in dept.deptno%type )
    is
        rc sys_refcursor;
        emp_rec emp%rowtype;
        dept_rec dept%rowtype;
    begin
        rc :=  get_details_by_dno( p_tab , p_dno );
    
        if p_tab = 'EMP' then
            fetch rc into emp_rec;
            while rc%found loop
                dbms_output.put_line('ename='||emp_rec.ename||' empno='||emp_rec.empno);   
                fetch rc into emp_rec;
            end loop;
        elsif p_tab = 'DEPT' then
            fetch rc into dept_rec;
            while rc%found loop
                dbms_output.put_line('dname='||dept_rec.dname);   
                fetch rc into dept_rec;
            end loop;
        end if;
    end;
    /
    

    让我们看看它运行:

    SQL> set serveroutput on
    SQL> exec print_details_by_dno('EMP',50)
    ename=TRICHLER empno=8085
    ename=VERREYNNE empno=8060
    ename=FEUERSTEIN empno=8061
    ename=PODER empno=8100
    
    PL/SQL procedure successfully completed.
    
    SQL> exec print_details_by_dno('DEPT',50)
    dname=HOUSEKEEPING
    
    PL/SQL procedure successfully completed.
    
    SQL>
    

    【讨论】:

      【解决方案3】:

      您需要从动态 sql 中声明一个游标并循环遍历它。

      手册中提供了一个示例:
      http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/dynamic.htm#CHDJHAHE

      【讨论】:

      • 在常规方法中不需要声明任何变量,所有的都是静态的,我希望它类似于常规方法,除了它必须是动态的。
      • 我对谷歌没有任何问题:)
      • 因此简化示例以获得您想要的 - OPEN emp_cv FOR 'SELECT * FROM ' ||表名;循环...结束循环;
      • 我在乎这一刻 OPEN emp_cv
      • 您不能只说 FOR items IN ('SELECT * FROM ' || table_name'),正如您可能已经发现的那样。所以你必须声明游标变量。
      【解决方案4】:
      TYPE RefCurTyp IS REF CURSOR;
      sql  VARCHAR2(200);
      cursor RefCurTyp;
      id  VARCHAR2(200);
      BEGIN
        sql := 'SELECT * FROM ' || table_name;
      
        OPEN cursor FOR sql;
        LOOP
          FETCH cursor INTO id;
      
          htp.p(id);     
      
          EXIT WHEN cursor%NOTFOUND;
        END LOOP;
      
        CLOSE cursor;
      END;
      

      【讨论】:

      • 我认为 table_name 引用了单个 varchar2 列表,因此 id 将包含该列的当前记录值
      猜你喜欢
      • 2022-06-11
      • 2018-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-11
      • 1970-01-01
      相关资源
      最近更新 更多