ВЫПОЛНИТЬ НЕМЕДЛЕННО в plsql

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

EXECUTE IMMEDIATE 'SELECT * FROM ' || table_name

через цикл for

Обычный метод выглядит так

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

person Жасулан Бердибе&    schedule 26.01.2011    source источник


Ответы (4)


Если вам действительно нужно 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;
/
person René Nyffenegger    schedule 26.01.2011
comment
Выражение «RESULT_SET» в списке INTO имеет неправильный тип. - person Жасулан Бердибе&; 27.01.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 в качестве фильтра; следовательно, функция не работает, если мы передаем таблицу, в которой нет такого столбца.

Некоторые клиенты могут интерпретировать метаданные курсора ссылки. Например, это могут делать наборы результатов JDBC и ODBC. 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>
person APC    schedule 26.01.2011

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

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

person a_horse_with_no_name    schedule 26.01.2011
comment
В обычном методе не нужно объявлять никаких переменных, просто там происходит все статично, и я хочу, чтобы он был похож на обычный метод, за исключением того, что он должен быть динамическим. - person Жасулан Бердибе&; 26.01.2011
comment
И у меня нет проблем с гуглом :) - person Жасулан Бердибе&; 26.01.2011
comment
Поэтому упростите пример, чтобы получить то, что ВЫ хотите: OPEN emp_cv FOR 'SELECT * FROM ' || имя_таблицы; ЦИКЛ ... КОНЕЦ ЦИКЛА; - person Tony Andrews; 26.01.2011
comment
Мне важен этот момент OPEN emp_cv - person Жасулан Бердибе&; 26.01.2011
comment
Вы не можете просто сказать ДЛЯ элементов IN ('SELECT * FROM ' || table_name'), как вы, вероятно, обнаружили. Поэтому вы ДОЛЖНЫ объявить переменную курсора. - person Tony Andrews; 26.01.2011

person    schedule
comment
Я считал, что table_name относится к таблице с одним столбцом varchar2, поэтому id будет содержать значение текущей записи для этого столбца. - person vc 74; 26.01.2011