Eduardo Corrêa Gonçalves
Instituto Brasileiro de Geografia e Estatística – IBGE
E-mail: eduardo.correa@ibge.gov.br
1. Introdução
O uso de comandos SQL montados de forma dinâmica - ou seja, em tempo de execução - corresponde a um dos recursos mais interessantes da linguagem PL/SQL (linguagem do SGBD Oracle). É possível executar dinamicamente não apenas consultas SQL ou comandos DML (INSERT, UPDATE e DELETE), mas também comandos DDL (como CREATE ou DROP) e DCL (como GRANT e REVOKE). Este artigo inicia uma série de trabalhos que abordarão as características e formas de implementação deste recurso em ambiente Oracle.
2. SQL Dinâmico: um Exemplo Simples
Um comando SQL Dinâmico representa uma instrução SQL que é construída e armazenada numa variável do tipo VARCHAR2 (o equivalente ao tipo “string” no mundo Oracle) durante a execução de uma função ou procedure PL/SQL. Esta instrução pode ser montada de diferentes maneiras, de acordo com parâmetros de entrada. Para facilitar a compreensão deste conceito, será apresentado um primeiro exemplo prático. Considere uma função que recebe o nome de duas tabelas como entrada e que, como saída, retorne numa string concatenada o nome e a quantidade de registros da tabela que possuir o maior número de registros. O código desta função é apresentado a seguir:
CREATE OR REPLACE FUNCTION F_MAIOR(vTAB1 IN VARCHAR, vTAB2 IN VARCHAR) RETURN VARCHAR IS
vSQL VARCHAR2(256); --string que recebe o comando SQL dinâmico
vTOT1 PLS_INTEGER; --total de registros da Tabela 1
vTOT2 PLS_INTEGER; --total de registros da Tabela 2
BEGIN
--PASSO 1: monta e executa SQL dinâmico referente a Tabela 1
vSQL := ‘SELECT COUNT(*) FROM ’ || vTAB1;
EXECUTE IMMEDIATE vSQL INTO vTOT1;
--PASSO 2: monta e executa SQL dinâmico referente a Tabela 2
vSQL := ‘SELECT COUNT(*) FROM ’ || vTAB2;
EXECUTE IMMEDIATE vSQL INTO vTOT2;
--PASSO 3: retorna o nome e a quantidade de registros da tabela com mais linhas
IF vTOT1 > vTOT2 THEN
RETURN vTAB1 || ‘ --- ’ || TO_CHAR(vTOT1);
ELSIF vTOT1 < vTOT2 THEN
RETURN vTAB2 || ‘ --- ’ || TO_CHAR(vTOT2);
ELSE
RETURN ‘EMPATE --- ’ || TO_CHAR(vTOT2);
END IF;
END;
O programa exemplo funciona da seguinte forma. No passo 1, uma instrução SQL é montada dinamicamente e armazenada na variável vSQL (do tipo VARCHAR2). Observe que o parâmetro de entrada da função vTAB1 (nome da tabela 1) é concatenado no final do literal ‘SELECT COUNT(*)’. A seguir encontra-se a linha de código mais importante do programa:
EXECUTE IMMEDIATE vSQL INTO vTOT1;
O comando EXECUTE IMMEDIATE é o responsável pela interpretação e execução de instruções SQL montadas de forma dinâmica. Para realizar esta tarefa, basta especificar a string SQL (no exemplo, vSQL) e o nome da variável que armazenará o resultado obtido pela execução do SQL (no exemplo, o resultado corresponde ao total de registros da tabela vTAB1 e será armazenado na variável vTOT1).
O passo 2 do programa é semelhante ao passo 1. A única diferença é o fato de que agora o SQL dinâmico armazenado em vSQL será montado com o nome do parâmetro vTAB2 no final (nome da segunda tabela cuja quantidade de registros deseja-se determinar). Finalizando a função, o passo 3 simplesmente testa qual é a tabela que contém mais linhas e retorna essa informação ao usuário.
Para criar a função, basta executar o SQL Plus, efetuar o login em uma base Oracle e copiar e colar o código. Para executá-la, você pode utilizar, por exemplo, a seguinte chamada:
SQL> SELECT F_MAIOR(‘USER_TABLES’, ‘USER_VIEWS’) FROM DUAL;
F_MAIOR('USER_TABLES','USER_VIEWS')
--------------------------------------------------------------------------------
USER_TABLES --- 152
Neste exemplo, o Oracle compara a quantidade de registros das views de sistema USER_TABLES e USER_VIEWS e indica qual das duas retorna mais linhas.
3. Próximos Artigos
No próximo artigo desta série serão detalhadas as características do comando EXECUTE IMMEDIATE. Este comando é o mais utilizado para a implementação de SQL’s dinâmicos no PL/SQL, sendo empregado toda vez que se deseja executar comandos DDL, DCL e DML e consultas que retornem apenas uma linha. No entanto, quando o objetivo é processar consultas dinâmicas que resultarão em muitas linhas é preciso utilizar outro recurso do Oracle: os cursores dinâmicos. Estes cursores são implementados através dos comandos OPER-FOR, FETCH e CLOSE. Os cursores dinâmicos serão o tema do terceiro artigo sobre SQL dinâmico no Oracle.