ВЫПОЛНИТЬ НЕМЕДЛЕННО в plsql - PullRequest
2 голосов
/ 26 января 2011

Как получить результат из этого кода

EXECUTE IMMEDIATE 'SELECT * FROM ' || table_name

до для цикла

Обычный метод выглядит следующим образом

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

Ответы [ 4 ]

7 голосов
/ 26 января 2011

Если вам действительно нужно select * from имя динамической таблицы , то я, вероятно, выберу dbms_sql

Тип для записи :

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

Тип для результирующего набора (который представляет собой массив records ):

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;
/
6 голосов
/ 26 января 2011

Вот простая функция, которая динамически открывает переменную курсора, используя переданный параметр имени таблицы.

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 в качестве фильтра; следовательно, функция завершится ошибкой , если мы передадим таблицу, у которой нет такого столбца

Некоторые клиенты могут интерпретировать метаданные ref-курсора. Например, 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>
4 голосов
/ 26 января 2011

Вам нужно объявить курсор из динамического sql и пройти через него.

Пример этого доступен в руководстве:
http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/dynamic.htm#CHDJHAHE

3 голосов
/ 26 января 2011
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;
...