Доступ к имени таблицы в предложении from запроса из функции PL / SQL - PullRequest
1 голос
/ 04 июня 2011

Предположим, я запускаю запрос:

select MyProc(id) from tableName;

Есть ли способ получить доступ к tableName, используемому в предложении from в вышеприведенном запросе, из процедуры: MyProc ()?

Тогда я мог бы динамически использовать «из таблицы» в процедуре MyProc (). '

Спасибо.

Ответы [ 3 ]

2 голосов
/ 05 июня 2011

Нет, вы не можете этого сделать.Вы можете отправить таблицу в качестве параметра процедуры и использовать динамический SQL внутри вашей процедуры:

SELECT MyProc( id, 'tablename' ) FROM dual;

Но даже это неудобно и имеет все ограничения динамического SQL.Почему вашей процедуре нужно имя таблицы?Что вы пытаетесь сделать?

0 голосов
/ 05 июня 2011
create or replace function myProc(p_id number) return varchar2 is
    v_sql_id varchar2(13);
    v_table_name varchar2(100);
begin
    --Get the SQL used to call this function
    select sql_id into v_sql_id
    from v$sql
    where lower(sql_text) like 'select myproc(id)%'
        and users_executing > 0;

    --Get the table name
    select object_name into v_table_name
    from v$sql_plan
    where sql_id = v_sql_id
        and operation = 'TABLE ACCESS';

    --For testing, return the table name.
    return v_table_name;
end;
/

create table test1(id number);
create table test2(id number);
insert into test1 values(1);
insert into test2 values(2);
commit;

--Returns TEST1 (careful, your IDE may add this comment to the SQL!)
select MyProc(id) from test1;

--Returns TEST2
select MyProc(id) from test2;

Идея состоит в том, чтобы найти исполняемый в настоящий момент SQL, а затем найти таблицу, используемую этим SQL.Но есть много потенциальных проблем.

Получение SQL_ID

Есть много способов найти SQL_ID, но ни один из них не работает хорошо.Вот подходы, которые я попробовал, может быть, кто-то может выяснить, как заставить один из них работать лучше.

Например, в v $ session SQL_ID будет ссылаться на себя, а PREV_SQL_ID ссылается на некоторый бесполезный запрос транзакции (по крайней мере, в моей системе).

select sql_id, prev_sql_id from v$session where sid = sys_context('USERENV', 'SID');

Поиск запроса в v $ sql и упорядочение LAST_LOAD_TIME не всегда работает, LAST_LOAD_TIME не всегда обновляется.

select sql_id from v$sql
where lower(sql_text) like 'select myproc(id)%'
order by last_load_time desc;

ИспользованиеSQL_TEXT и USERS_EXECUTING> 0 будут работать, но только если только один сеанс одновременно выполняет этот запрос.И искать такой текст очень опасно.Некоторые среды могут помещать текст перед выбором, например, пробелы или комментарии.Но вы не можете искать «% select ...», потому что тогда запрос вернется сам.

select sql_id into v_sql_id
from v$sql
where lower(sql_text) like 'select myproc(id)%'
    and users_executing > 0;

Поиск таблицы

С помощью SQL_ID мыможет легко получить текст запроса из v $ sql.sql_text или v $ sql.sql_fulltext. может быть возможным для вас, чтобы проанализировать этот запрос, но в целом я бы рекомендовал вам не разбирать SQL.Это гораздо сложнее, чем думает большинство людей.Если вы абсолютно уверены, что будет использоваться только конкретный простой запрос, то, возможно, этот подход будет работать.

Более реалистичный подход, вероятно, заключается в использовании v $ sql_plan для поиска используемых таблиц.Это будет работать для вашего запроса, но вам придется выполнять больше работы, если в вашем запросе может быть несколько таблиц, или если есть представления или индексы (вам нужно присоединиться к user_index, чтобы найти фактическую таблицу),и т. д.

select object_name
from v$sql_plan
where sql_id = <SQL_ID>
    and operation = 'TABLE ACCESS'

Возможно, вам потребуется предоставить пользователю select для v_ $ sql и v_ $ sql_plan.Ох, и это будет очень медленно.Идея @ Иолсона о передаче имени таблицы в качестве параметра намного лучше, если она работает.

0 голосов
/ 05 июня 2011

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

strSQL  VARCHAR2(32767);
csr     SYS_REFCURSOR;
nVal1    NUMBER;
nVal2    NUMBER;
strVal3  VARCHAR2(2000);

strSQL := 'SELECT val1, val2, val3 FROM ' || tableName || ' WHERE whatever = somethingelse';

OPEN csr FOR strSQL;
FETCH csr INTO nVal1, nVal2, strVal3;
CLOSE csr;

Делись и наслаждайся.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...