quarta-feira, 1 de maio de 2013

Tornando um PL/SQL dinâmico, utilizando a opção EXECUTE IMMEDIATE


O comando EXECUTE IMMEDIATE está presente no “package” DBMS_SQL desde a versão 8i. Este comando permite executar imediatamente um SQL ou um bloco PL/SQL durante a sua criação. 

Muitas vezes a criação e execução de SQL’s dinâmicos podem comprometer significativamente o desempenho do banco de dados. Porém o comando “execute immediate” reduz esse problema e ajuda a obter um desempenho melhor, além de tornar mais amigável a programação de códigos PL/SQL.

A partir da versão do Oracle 11g o comando “execute immediate” permite o uso de tipos de dados CLOB como um argumento.

Dicas de uso 

§  O comando “execute immediate” não grava uma transação de DML, para gravá-lo uma instrução de “commit” deverá ser executada.  Já um comando DDL, quando processado via “execute immediate”, será gravado diretamente.

§  Para consultas que retornam mais de uma linha este comando não é suportado, como alternativa deve-se criar uma tabela temporária para gravar os registros (ver exemplo abaixo), ou usar cursores do tipo REF.


Abaixo são apresentadas as possibilidades para utilizar o comando “execute immediate”.

Exemplos

1.    Executando um comando DDL em um código PL/SQL.

  begin   
    execute immediate 'set role all';
  end;

2.    Passando valores para um SQL dinâmico (utilizando a cláusula – USING).

declare
l_depnome varchar2(20) := 'TESTE';
l_local    varchar2(10) := 'Brasil';
 
begin
 execute immediate 'insert into dept values (:1, :2, :3)'
   using 50, l_depnome, l_local;
 commit;
end;
 
 
3.    Retornando valores de um SQL dinâmico (utilizando a cláusula – INTO).

declare
 l_cnt    varchar2(20);
 
begin
 execute immediate 'select count(1) from emp'
   into l_cnt;
 dbms_output.put_line(l_cnt);
end;
 
 
4.    Chamando uma rotina dinamicamente.
 
 l_rotina   varchar2(100) := 'gen2161.get_rowcnt';
 l_nome_tbl varchar2(20) := 'emp';
 l_cnt      number;
 l_status   varchar2(200);
 
begin
 execute immediate 'begin ' || l_rotina || '(:2, :3, :4); end;'
   using in l_nome_tbl, out l_cnt, in out l_status;
 
 if l_status != 'OK' then
    dbms_output.put_line('Erro !');
 end if;
end;
 
 
5.    Retornando um valor para dentro de um registro em um código PL/SQL. A mesma opção pode ser usada para variáveis do tipo “%rowtype”.

declare
 type empdtlrec is record (empno  number(4),
                           ename  varchar2(20),
                           deptno  number(2));
 empdtl empdtlrec;
 
begin
 execute immediate 'select empno, ename, deptno ' ||
                   'from emp where empno = 7934'
   into empdtl;
end;
 
 
6.    Passando e retornando valores. Na cláusula INTO deve-se utilizar a cláusula USING.
 
declare
 l_dept    pls_integer := 20;
 l_nam     varchar2(20);
 l_loc     varchar2(20);
 
begin
 execute immediate 'select dname, loc from dept where deptno = :1'
   into l_nam, l_loc
   using l_dept ;
end;
 
 
7.    Para consultas que retornem mais de uma linha. Usar o comando “insert” para popular uma tabela temporária.
 
declare
 l_sal   pls_integer := 2000;
begin
 execute immediate 'insert into temp(empno, ename) ' ||
                   '  select empno, ename from emp ' ||
                   '   where  sal > :1'
   using l_sal;
 commit;
end;
 

Importante:  O comando “execute immediate” possui um método muito mais fácil e eficiente para processar SQL’s dinâmicos. Porém não esquecer que quando a intenção é executar SQL’s dinâmicos, o tratamento de exceções torna-se muito importante.


Referências: Oracle® Database PL/SQL Language Reference 11g Release 2 (11.2) 



MSc. Rubens Oliveira
DBA Oracle Consultor
olivert.dba@consultant.com