Os controles de declarações são realizados em três categorias, as quais são a de declarações condicionais de seleção, declarações em loop (repetitivas) e as declarações de controle em sequência. Cada uma delas tem suas particularidades, as quais veremos no decorrer dos artigos. Cada uma das estruturas trabalha de forma diferente como podemos ver pelas estruturas de seleção, onde estas, para testar uma determinada condição, realizam uma sequência de instruções para que dependendo do resultado, sendo este verdadeiro ou falso, tenhamos um resultado. No caso, essa condição necessária pode ser qualquer variável ou expressão que retorne um valor do tipo booleano. Já com relação a estruturas em Loop e as estruturas de repetição têm por finalidade executar sequências de declarações de forma repetida enquanto a condição especificada não tenha sido condicionada verdadeira. E por último temos as estruturas sequenciais, as quais são executadas em uma sequência de comandos simples na ordem em que foram especificadas.
Trabalhando com o IF
Quando trabalhamos com as instruções IF no Oracle, estas são utilizadas para a execução de código para quando uma condição for satisfeita, ou seja, quando esta for verdadeira, em caso de apresentar um resultado diferente, ela executará uma outra estrutura de código. Os IF’s são executados em uma dada sequência de instruções, onde temos três formas de apresentação desta instrução: IF-THEN, IF-THEN-ELSE e IF-THEN-ELSEIF. A partir de agora veremos cada uma dessas estruturas, começando pela sintaxe básica de sua utilização, como podemos ver de acordo com as Listagens 1, 2 e 3.
Listagem 1. Sintaxe básica do IF-THEN.
IF condition THEN
{...As instruções que serão executadas vão aqui quando a condição é TRUE...}
END IF;
Como podemos observar na Listagem 1, esta é a forma mais simples de utilização da instrução que é associado a um estado a partir de uma sequência de instruções apresentada entre as palavras-chave THEN e END IF. Neste caso, a sequência de instruções é executada somente quando esta for verdadeira. Em caso de termos um retorno NULL ou mesmo FALSE, a instrução não fará nada.
A segunda forma de instrução IF tem a adição de uma nova palavra-chave, ELSE, a qual apresenta uma sequência de instruções alternativa para o processo. A sua sintaxe básica pode ser vista de acordo com a Listagem 2. Neste caso, as afirmações contidas na cláusula ELSE São executadas quando a condição for FALSE.
Listagem 2. Sintaxe básica do IF-THEN-ELSE.
IF condition THEN
{...As instruções que serão executadas vão aqui quando a condição é TRUE...}
ELSE
{...As instruções que serão executadas vão aqui quando a condição é FALSE...}
END IF;
Em caso de termos a necessidade de escolha entre várias alternativas podemos utilizar a palavra-chave ELSIF que é responsável por introduzir condições adicionais a nossa instrução básica, como podemos ver de acordo com a Listagem 3.
Listagem 3. Sintaxe da instrução IF-THEN-ELSIF.
IF condition1 THEN
{...As instruções que serão executadas vão aqui quando a condição é TRUE...}
ELSIF condition2 THEN
{...As instruções que serão executadas vão aqui quando a condição é TRUE...}
END IF;
Caso da primeira condição resultar em FALSE ou NULL, a cláusula ELSIF realizará o teste da outra condição especificada. Uma instrução IF pode ter mais de uma cláusula ELSIF, onde temos que a cláusula ELSE no fim de toda operação é opcional. Se alguma condição for verdadeira, a sua sequência de declarações associada é executada e o controle passa para a próxima instrução. Em caso de todas as instruções resultarem em FALSE, a cláusula ELSE é então executada. Com base no que foi dito até o momento vejamos um exemplo de cada uma das instruções para que o conceito seja melhor aproveitado, como mostram os exemplos das Listagens 4, 5 e 6.
Listagem 4. Exemplo da instrução IF-THEN.
DECLARE
precoVenda NUMBER(10,2) := 300;
cota NUMBER(8,2) := 500;
bonificacao NUMBER(5,2);
codFunc NUMBER(6) := 15;
BEGIN
IF precoVenda > (cota + 100) THEN
bonificacao := (precoVenda - cota)/4;
UPDATE funcionario SET salarioFunc = salarioFunc + bonificacao
WHERE funcionario_id = codFunc;
END IF;
END;
/
Listagem 5. Exemplo da instrução IF-THEN-ELSE.
DECLARE
precoVenda NUMBER(8,2) := 400;
cota NUMBER(8,2) := 10;
bonificacao NUMBER(6,2);
codFunc NUMBER(6) := 20;
BEGIN
IF precoVenda > (cota + 30) THEN
bonificacao := (precoVenda - cota)/4;
ELSE
bonificacao := 100;
END IF;
UPDATE funcionario
SET salarioFunc = salarioFunc + bonificacao
WHERE funcionario_id = codFunc;
END;
/
Listagem 6. Exemplo da instrução IF-THEN-ELSIF.
DECLARE
precoVenda NUMBER(8,2) := 200;
bonificacao NUMBER(6,2);
codFunc NUMBER(6) := 120;
BEGIN
IF precoVenda > 6000 THEN
bonificacao := 1200;
ELSIF precoVenda > 3500 THEN
bonificacao := 250;
ELSE
bonificacao := 100;
END IF;
UPDATE funcionario SET salarioFunc = salarioFunc + bonificacao
WHERE funcionario_id = codFunc;
END;
/
Além das formas apresentadas podemos ter estruturas de IF’s aninhados, o que no caso, seriam estruturas IF’s dentro de outras condições de controles IF’s, como podemos ver de acordo com a Listagem 7.
Listagem 7. Exemplo de IF’s encadeados (ou aninhados).
DECLARE
precoVenda NUMBER(8,2) := 21000;
cota NUMBER(8,2) := 1000;
bonificacao NUMBER(6,2);
codFunc NUMBER(6) := 150;
BEGIN
IF precoVenda > (cota + 50) THEN
bonificacao := (precoVenda - cota)/4;
ELSE
IF precoVenda > cota THEN
bonificacao := 70;
ELSE
bonificacao := 0;
END IF;
END IF;
UPDATE funcionario
SET salarioFunc = salarioFunc + bonificacao
WHERE funcionario_id = codFunc;
END;
/
Veja que apresentamos uma estrutura de IF’s aninhados, onde quando uma condição inicial não é satisfeita, passamos para o ELSE da condição e nele temos uma nova condição sendo apresentada. Dessa forma, se o valor das vendas for maior do que 21000, as primeiras e segundas condições serão TRUE. No entanto, o bônus é atribuído o valor adequado de 5000 porque a segunda condição nunca é testada. Quando a primeira condição for verdadeira, a sua declaração de associado é executada e o controle passa para a instrução de UPDATE.
Instrução CASE
A instrução CASE é uma forma mais compacta para realizar a avaliação de uma única condição e escolher entre algumas ações alternativas. No caso de termos mais de dois IF’s, de certa forma, passa a ser mais aplicável a utilização de CASES. Para que possamos entender melhor com relação a estrutura do CASE, vejamos como é declarada a sua sintaxe básica de acordo com a Listagem 8.
Listagem 8. Sintaxe básica da instrução CASE.
CASE [ expression ]
WHEN condition_1 THEN result_1
WHEN condition_2 THEN result_2
...
WHEN condition_n THEN result_n
ELSE result
END
Assim como a declaração IF, a instrução CASE seleciona uma sequência de instruções para executar, como podemos observar pela Listagem 8. No entanto, para que possamos selecionar esta sequência, a instrução CASE usa um parâmetro ao invés de múltiplas expressões booleanas. Quando nos referimos a um “parâmetro”, este pode ser uma expressão onde um valor é utilizado para selecionar uma dentre as várias alternativas apresentadas. Vejamos então de acordo com a Listagem 9 um exemplo de sua utilização.
Listagem 9. Utilizando a instrução CASE.
DECLARE
nota integer;
BEGIN
nota := 9;
CASE nota
WHEN 10 THEN DBMS_OUTPUT.PUT_LINE('Nota Excelente');
WHEN 9 THEN DBMS_OUTPUT.PUT_LINE('Nota muito boa');
WHEN 8 THEN DBMS_OUTPUT.PUT_LINE('Boa nota');
WHEN 7 THEN DBMS_OUTPUT.PUT_LINE('Nota na média');
WHEN 6 THEN DBMS_OUTPUT.PUT_LINE('Nota abaixo da média');
ELSE DBMS_OUTPUT.PUT_LINE('Sem classificação de notas');
END CASE;
END;
/
Com a instrução CASE torna-se mais legível e mais eficiente a leitura do código, o que além de tudo, elimina a criação de uma estrutura longa de declarações do tipo IF-THEN-ELSIF’s quando passadas para uma declaração CASE. Como podemos observar na Listagem 9, temos a declaração CASE iniciada com a palavra-chave CASE. A palavra-chave é seguida por um parâmetro, sendo este o parâmetro que definimos na cláusula DECLARE. Muitas vezes os parâmetros utilizados como seletores podem ser um pouco mais complexos, como por exemplo, quando estes contêm chamadas de funções. O que podemos desconsiderar no momento, pois na maior parte das vezes trabalhamos apena com variáveis. O parâmetro é avaliado uma única vez, em seguida, o valor que ele produz pode ter qualquer tipo de dados PL/SQL diferente como podemos citar BLOB, BFILE, índices, dentre várias outras tipagens que possamos compreender.
O parâmetro seletor é então seguido por uma ou mais cláusulas que são verificadas de forma sequencial. Em meio a pesquisa que é feita, o valor do parâmetro é quem determina qual cláusula será executada e se o valor do parâmetro for igual ao valor de uma clausula com a expressão WHEN, esta é quem será executada. Como podemos observar pela Listagem 9, caso a nota seja igual a ‘C’, o resultado será “8 - Boa nota”. Como também podemos observar, temos a cláusula ELSE presente nas instruções WHEN do CASE, e para esta instrução não há diferença de uso quanto as utilizadas nas condições IF. No caso de passamos por todas as opções WHEN e não obtivermos um resultado, cairemos então no ELSE e este se encarregará de nos apresentar a mensagem de saída. Em caso de omitirmos a cláusula ELSE, o Oracle possui uma mensagem padrão em caso da não correspondência com nenhuma das cláusulas WHEN, que no caso seria a seguinte exceção apresentada:
CASE_NOT_FOUND;
Utilizando Instruções CASE Searched
No PL/SQL temos também o recurso CASE Searched, o qual é bastante semelhante às instruções simples do CASE, com a diferença de que nesta forma o CASE não possui parâmetros de entrada e em suas cláusulas WHEN temos condições de pesquisa que retornam valores booleanos ao invés de expressões que podem ter valores de qualquer tipo, como mostra a Listagem 10. Usaremos o mesmo exemplo da Listagem 9 para que possamos apresentar como ter uma CASE Searched (CASE Pesquisada).
Listagem 10. Utilizando uma Case Searched.
DECLARE
nota INTEGER;
BEGIN
nota := 7;
CASE
WHEN nota = 10 THEN DBMS_OUTPUT.PUT_LINE('Nota Excelente');
WHEN nota = 9 THEN DBMS_OUTPUT.PUT_LINE('NOta muito boa');
WHEN nota = 8 THEN DBMS_OUTPUT.PUT_LINE('Boa nota');
WHEN nota = 7 THEN DBMS_OUTPUT.PUT_LINE('Nota média');
WHEN nota = 5 THEN DBMS_OUTPUT.PUT_LINE('Nota abaixo da média');
ELSE DBMS_OUTPUT.PUT_LINE('Sem classificação de notas');
END CASE;
END;
/
Como podemos observar nas Listagens 9 e 10 a cláusula ELSE, que poderia ser substituída por uma instrução de exceção, como podemos observar de acordo com a Listagem 11.
Listagem 11. CASE com EXCEPTION.
DECLARE
nota INTEGER;
BEGIN
nota := 3;
CASE
WHEN nota = 10 THEN DBMS_OUTPUT.PUT_LINE('Nota Excelente');
WHEN nota = 9 THEN DBMS_OUTPUT.PUT_LINE('Nota muito boa');
WHEN nota = 8 THEN DBMS_OUTPUT.PUT_LINE('Boa nota');
WHEN nota = 7 THEN DBMS_OUTPUT.PUT_LINE('Nota média');
WHEN nota = 5 THEN DBMS_OUTPUT.PUT_LINE('Nota abaixo da média');
END CASE;
EXCEPTION
WHEN CASE_NOT_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Sem classificação de notas');
END;
/
Como podemos perceber, as condições de pesquisa são avaliadas sequencialmente, onde o valor booleano de cada condição de pesquisa determina qual das cláusulas WHEN será executada. Em caso de nenhuma das condições apresentadas ser TRUE, a cláusula ELSE será executada e como sabemos, esta é opcional e quando omitida, o PL/SQL apresenta uma cláusula ELSE explicitamente, que é:
ELSE RAISE CASE_NOT_FOUND;
Trabalhando com Instruções LOOP
A partir desse momento estaremos trabalhando com os Loops no Oracle, que nada mais são que estruturas de repetição. No Oracle podemos utilizar os Loops para rodar as mesmas estruturas de formas diferentes com diferentes valores. Os loops realizam a execução de sequências de instruções até alcançar o objetivo. As estruturas de Loop no Oracle são o Loop Básico, For Loop, Cursos Loop e o While Loop. Veremos cada um deles no decorrer do artigo. Começaremos então pelo Loop básico, no qual veremos primeiramente a sua sintaxe, de acordo com a Listagem 12.
Listagem 12. Sintaxe básica do Loop Básico.
[ label ] LOOP
statements
END LOOP [ label ];
Veja que temos em que cada iteração do loop as declarações sendo executadas e o controle passa de volta para o começo da instrução do loop. Para que não tenhamos loops infinitos precisamos utilizar declarações que finalizem o Loop ao encontrar uma resposta ou não, como é o caso do EXIT e do CONTINUE. Para que possamos entender melhor a sua utilização, vejamos de acordo com a Listagem 13 como podemos utilizar o Loop básico.
Listagem 13. Exemplo básico de utilização do Loop.
DECLARE
valor NUMBER := 0;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE (' No interior do loop, temos o valor = ' || TO_CHAR(valor));
valor := valor + 1;
IF valor > 40 THEN
EXIT;
END IF;
END LOOP;
-- após a entrada na instrução EXIT, o controle é encerrado.
DBMS_OUTPUT.PUT_LINE(' Após o Loop com valor = ' || TO_CHAR(valor));
END;
/
O que podemos perceber é a iteração do Loop, que é incrementada de valor +1 a cada vez que realiza a validação na condição IF de que o valor final ainda não foi alcançado e, dessa forma, dando seguimento ao fluxo. Além dessa forma de utilização podemos ainda utilizá-lo de forma aninhada ou mesmo com a cláusula WHEN.
Quando utilizamos a declaração EXIT WHEN, ela sai da iteração atual do ciclo quando a condição da cláusula WHEN é verdadeira, no caso TRUE. Ocorrendo essa validação, o controle é transferido para o fim do loop. Vejamos então um exemplo simples de utilização na Listagem 14.
Listagem 14. Utilizando o EXIT WHEN no Loop Básico.
DECLARE
valor NUMBER := 0;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE('Dentro do loop, temos o valor = ' || TO_CHAR(valor));
valor := valor + 1;
EXIT WHEN valor > 10;
END LOOP;
-- Após a instrução EXIT, o controle é encerrado e apresenta o último valor visto.
DBMS_OUTPUT.PUT_LINE('Após o último registro do loop verificado, temos o valor = ' || TO_CHAR(valor));
END;
/
Temos a utilização da cláusula EXIT WHEN, que determina a saída da operação ao chegarmos ao valor 10. Vejamos agora um exemplo simples de como trabalhar com os Loops Básicos aninhados, como mostra a Listagem 15.
Listagem 15. Exemplo de utilização de Loops Básicos aninhados.
DECLARE
s INTEGER := 0;
i INTEGER := 0;
j INTEGER;
BEGIN
<<outer_loop>>
LOOP
i := i + 1;
j := 0;
<< inner_loop >>
LOOP
j := j + 1;
s := s + i * j; -- Soma realizada de produtos
EXIT inner_loop WHEN (j > 8);
EXIT outer_loop WHEN ((i * j) > 26);
END LOOP inner_loop;
END LOOP outer_loop;
DBMS_OUTPUT.PUT_LINE
('A soma do valor dos produtos é igual a: ' || TO_CHAR(s));
END;
/
Ao encerrar o controle interno de operações foi passado para o fluxo externo e então foram realizadas as operações e em seguida a finalização do processo. Também podemos utilizar a declaração EXIT WHEN em fluxos aninhados, como podemos ver na Listagem 16.
Listagem 16. Utilização de Loops aninhados com cláusulas EXIT WHEN.
DECLARE
i INTEGER := 0;
j INTEGER := 0;
BEGIN
LOOP
i := i + 1;
DBMS_OUTPUT.PUT_LINE ('o valor de i é: ' || i);
LOOP
j := j + 1;
DBMS_OUTPUT.PUT_LINE ('O valor de j é:' || j);
EXIT WHEN (j > 8);
END LOOP;
DBMS_OUTPUT.PUT_LINE ('Saindo do loop interno');
EXIT WHEN (i > 6);
END LOOP;
DBMS_OUTPUT.PUT_LINE ('Saindo do Loop externo');
END;
/
Com os exemplos apresentados podemos ter uma noção básica de como podemos trabalhar com os Loops básicos e as cláusulas EXIT WHEN e EXIT. O que falta vermos é a utilização da cláusula CONTINUE, que no caso, sai da iteração atual de um laço incondicionalmente e em seguida passa o controle para a próxima iteração do loop. Nas Listagens 17 e 18 trabalharemos com o Loop básico e o CONTINUE WHEN.
Listagem 17. Loop básico com cláusula CONTINUE.
DECLARE
valor NUMBER := 0;
BEGIN
LOOP – Após a declaração CONTINUE
DBMS_OUTPUT.PUT_LINE ('Valor apresentado no interior do loop é igual a: ' || TO_CHAR(valor));
valor := valor + 1;
IF valor < 15 THEN
CONTINUE;
END IF;
DBMS_OUTPUT.PUT_LINE
('No interior do loop, após a cláusula CONTINUE, o valor é igual a: ' || TO_CHAR(valor));
EXIT WHEN valor = 5;
END LOOP;
DBMS_OUTPUT.PUT_LINE ('Após o loop, o valor é igual a: ' || TO_CHAR(valor));
END;
/
Quando utilizamos a declaração CONTINUE WHEN, ela sai da iteração atual do ciclo quando a condição em sua cláusula WHEN é apresentada como TRUE, e em seguida, transfere o controle para a próxima iteração do loop.
Listagem 18. Cláusula CONTINUE com a utilização da cláusula CONTINUE WHEN.
DECLARE
valor NUMBER := 0;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE ('Dentro do Loop o valor é igual a: ' || TO_CHAR(valor));
valor := valor + 1;
CONTINUE WHEN valor < 8;
DBMS_OUTPUT.PUT_LINE
(‘Após a cláusula CONTINUE, o valor é igual a: ' || TO_CHAR(valor));
EXIT WHEN valor = 7;
END LOOP;
DBMS_OUTPUT.PUT_LINE ('Após o loop, o valor é igual a:' || TO_CHAR(valor));
END;
/
Com isso finalizamos este artigo, onde tivemos a introdução ao uso de estruturas de controle com o Oracle 12C, sua utilização, sua sintaxe em cada caso e como podemos utilizá-las em nossas aplicações de forma simples e objetiva. Esperamos que tenham gostado e até a próxima! =)