在plsql中执行IMMEDIATE

时间:2011-01-26 10:12:39

标签: sql oracle plsql cursor dynamic-sql

如何从此代码中获取结果

EXECUTE IMMEDIATE 'SELECT * FROM ' || table_name

通过 for循环

通常的方法看起来像这样

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

4 个答案:

答案 0 :(得分:7)

如果确实需要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;
/

执行select并返回结果集的实例的函数:

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

答案 1 :(得分:6)

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

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 ResultSet可以执行此操作。 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>

答案 2 :(得分:4)

你需要从动态sql声明一个游标并循环它。

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

答案 3 :(得分:3)

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;