Banco de Dados - Oracle
Cursores no Oracle – Parte 2 - OS LOOPs
Neste segundo artigo da série sobre os cursores no Oracle, vou falar um pouquinho sobre os laços de repetição - os famosos LOOPs!
por Danielle MonteiroNeste segundo artigo sobre cursores no Oracle, vamos falar sobe os laços de repetição. Os famosos LOOPs.
Temos diversos tipos de loop e eles devem ser usados de acordo com a sua necessidade. Estes laços podem ser usados com diversos objetos não só com cursores, por isso os primeiros exemplos não serão com cursores, mas no final, como de costume vou criar uma package com procedures exemplificando cada um dos tipos de laço.
Vamos começar dizendo conceitualmente o que é um Laço de Repetição: São comandos que executam outros comandos repetidas vezes.
Vamos então aos tipos de Laço:
LOOP
Este tipo de laço executa uma seqüência de comandos contida entre seu início e fim, ou seja executa infinitas vezes tudo o que estiver entre os comandos LOOP – END LOOP.
Este laço é infinito, por isso junto com ele usamos um dos seguintes comandos EXIT ou EXIT – WHEN. Estes comandos servem para interromper um loop.
EXIT
Este comando sai do loop imediatamente. Quando este comando é encontrado, o LOOP é imediatamente encerrado, e o controle é passado para o próximo comando. Este comando deve estar dentro do LOOP.
EXIT – WHEN
Este commando termina o loop de maneira condicional. Quando o comando EXIT é encontrado a condição da claúsula WHEN é verificada. Se a condição for verdadeira, o loop é interrompido, e o controle é passado para o próximo comando.
Vamos exemplificar o uso destes três comandos de maneira simples (como eu disse no começo, após mostrar a sintaxe dos laços eu criarei uma package que poderá ser testada).
LOOP
-- Comandos que serão executados infinitamente
END LOOP;
Exemplo 1 – Um loop infinito
LOOP
-- Comandos que devem ser executados
IF Variavel_Criada_Instanciada > valor_Exemplo THEN
EXIT;
END IF;
END LOOP;
Exemplo 2 – Um loop que será interrompido ao encontrar o comando EXIT;
LOOP
EXIT WHEN Variavel_Criada_Instanciada > valor_Exemplo ;
-- Comandos que devem ser executados
END LOOP;
Exemplo 3 – Um loop que será interrompido quando a condição da claúsula WHEN for verdadeira;
Ao observar os exemplos 2 e 3 fica claro que o exemplo 3 substitui o exemplo 2.
WHILE-LOOP
Este tipo de laço, executa uma seqüência de comandos enquanto a condição do comando WHILE for verdadeira.
Antes de cada iteração do loop a condição é checada, se ela for satisfeita os comandos serão executados, se a condição for falsa ou nula o loop será intrrompido e o controle passado para o próximo comando.
Ao usar este tipo de loop, temos que lembrar que a variável da condição deve ser manipulada dentro do loop, ou teremos um loop infinito.
WHILE Variavel_Criada_Instanciada <=1000 LOOP
--Comandos executados
Variavel_Criada_Instanciada = Variavel_Criada_Instanciada + Outra_Variave_ou_Constante;
END LOOP;
No exemplo acima, evitamos um loop infinito.
FOR – LOOP
Este tipo de laço o número de vezes que o comando será executado é informado.
Entre s palavras chave FOR e LOOP temos o esquema que controla o loop.
Veja a sintaxe deste tipo de laço:
FOR CONTADOR IN [REVESE] VALOR_INICIAL_DO_CONTADOR..VALOR_FINAL_DO_CONTADOR LOOP
--Comandos que serão executados
END LOOP;
O CONTADOR controlará o numero de vezes que o comando será executado dentro de um intervalo de valores entre o VALOR_INICIAL_DO_CONTADOR e o VALOR_FINAL_DO_CONTADOR (este intervalo é indicado pelo símbolo “..”).
A cada vez que os comandos são executados o valor do contador é incrementado.
Por padrão o valor do contador é incrementado, mas podemos também fazer o inverso, utilizando a palavra chave REVERSE antes de especificar o intervalo de valores.
O range pode ser especificado através de constantes, ou de variáveis, dependendo da necessidade e da lógica. Na package teremos 3 exemplos deste laço .
CONCLUSÃO
Os laços de repetição ajudam muito o desenvolvedor (independente da linguagem). No caso do PL/SQL é preciso que o desenvolvedor conheça a necessidade do objeto que está criando para que o seu loop funcione corretamente.
Não custa lembrar que é sempre bom verificar se as variáveis que fazem parte do conjunto de comandos do loop estão declaradas corretamente, se a regra de negócio está sendo respeitada, se a condição de saída do loop em algum momento será satisfeita entre outras verificações.
Abaixo temos um exemplo prático, onde criaremos uma package com procedures exemplificando todos estes loops, porém todas “varrem” um cursor. O conceito é o mesmo, só que agora estaremos manipulando um objeto.
Como nos artigos anteriores, todas as explicações estão nos comentários.
CREATE OR REPLACE PACKAGE PKG_EXEMPLOSCURSOR IS
/*#####################################################################
PROCEDURE QUE EXEMPLIFICARÁ UM LAÇO DO TIPO LOOP-END LOOP, COM A CONDIÇÃO DE SAÍDA
EXIT-WHEN
#####################################################################*/
procedure PrcTesteCursor_LOOP;
/*#####################################################################
PROCEDURE QUE EXEMPLIFICARÁ UM LAÇO DO TIPO LOOP-END LOOP, COM A CONDIÇÃO DE SAÍDA
EXIT...
#####################################################################*/
procedure PrcTesteCursor_LOOP_exit;
/*#####################################################################
PROCEDURE QUE EXEMPLIFICARÁ UM LAÇO DO TIPO WHILE LOOP-END LOOP
#####################################################################*/
procedure PrcTesteCursor_WHILE;
/*#####################################################################
Neste exemplo, "varreremos" o cursor com um laço do tipo FOR – LOOP
#####################################################################*/
procedure PrcTesteCursor_FOR1;
/*#####################################################################
Neste exemplo, "varreremos" o cursor com um laço do tipo FOR – LOOP, com um intervalo
variável
#####################################################################*/
procedure PrcTesteCursor_FOR2;
/*#####################################################################
Neste exemplo, "varreremos" o cursor com um laço do tipo FOR – LOOP, com um intervalo
variável, e decrescente
#####################################################################*/
procedure PrcTesteCursor_FOR3;
END;
CREATE OR REPLACE PACKAGE BODY PKG_EXEMPLOSCURSOR AS
/*#####################################################################
Neste exemplo, "varreremos" o cursor com um laço do tipo LOOP- END LOOP,
E interromperemos o laço com o uso de uma condição imposta pelos comandos EXIT- WHEN
#####################################################################*/
procedure PrcTesteCursor_LOOP As
--Declarando as variáveis que serão manipuladas
vID int;
vNome varchar2(100);
--Criando o cursor que fará um select na tabela de clientes...
cursor cC1 is
SELECT ID, NOME FROM TBLCLIENTE ORDER BY ID;
begin
dbms_output.put_line("*****EXEMPLO DE LAÇO USANDO LOOP- END LOOP COM A CONDIÇÃO EXIT- WHEN*****");
/* **Exemplo de Laço do tipo LOOP - END LOOP***/
--Abrindo o cursor
open cC1;
/* 1-) Instrução de início do loop*/
loop
dbms_output.put_line("********************************************************");
--2-) Atribuindo o retorno da consulta, às variáveis
fetch cC1
into vID, vNome;
/*
** Exemplo de uso dos comandos EXIT-WHEN**
3-) Aqui incluí a condição de interromper o loop quando terminarem os itens do cursor */
exit when cC1%notfound;
--4-) Escrevendo o valor das variáveis somente...
dbms_output.put_line("ID: " || vID);
dbms_output.put_line("Nome: " || vNome);
--5-) instrução para finalizar o loop
end loop;
--6-)Fechando o cursor para disponibilizar os recursos que estavam sendo utilizados
close cC1;
end PrcTesteCursor_LOOP;
/*#####################################################################
Neste exemplo, "varreremos" o cursor com um laço do tipo LOOP- END LOOP,
E interromperemos o laço com uma instrução EXIT
#####################################################################*/
procedure PrcTesteCursor_LOOP_exit As
--Declarando as variáveis que serão manipuladas
vID int;
vNome varchar2(100);
--Criando o cursor que fará um select na tabela de clientes...
cursor cC1 is
SELECT ID, NOME FROM TBLCLIENTE ORDER BY ID;
begin
dbms_output.put_line("*****EXEMPLO DE LAÇO USANDO LOOP- END LOOP E INTERROMPIDO COM O COMANDO EXIT (QUE DEVE SER USADO SOMENTE EM LOOPS!)*****");
/* **Exemplo de Laço do tipo LOOP - END LOOP***/
--Abrindo o cursor
open cC1;
/* 1-) Instrução de início do loop*/
loop
dbms_output.put_line("********************************************************");
--2-) Atribuindo o retorno da consulta, às variáveis
fetch cC1
into vID, vNome;
/*
** Exemplo de uso dos comandos EXIT-WHEN**
3-) Aqui incluí a condição de interromper o loop quando terminarem os itens do cursor */
exit when cC1%notfound;
--4-) Verificando se o ID do usuário é maior que 3, se a condição for verdadeira, o loop será interrompido
--OBS: Veja que a procedure PrcTesteCursor_WHILE é equivalente a esta!
if vID > 3 then
exit;
end if;
--5-) Escrevendo o valor das variáveis somente...
dbms_output.put_line("ID: " || vID);
dbms_output.put_line("Nome: " || vNome);
--6-) instrução para finalizar o loop
end loop;
--7-)Fechando o cursor para disponibilizar os recursos que estavam sendo utilizados
close cC1;
end PrcTesteCursor_LOOP_exit;
/*#####################################################################
Neste exemplo, "varreremos" o cursor com um laço do tipo WHILE LOOP- END LOOP
#####################################################################*/
procedure PrcTesteCursor_WHILE As
--Declarando as variáveis que serão manipuladas
vID int :=0;
vNome varchar2(100);
--Criando o cursor que fará um select na tabela de clientes...
cursor cC1 is
SELECT ID, NOME FROM TBLCLIENTE ORDER BY ID;
begin
dbms_output.put_line("*****EXEMPLO DE LAÇO USANDO WHILE LOOP- END LOOP*****");
/* **Exemplo de Laço do tipo WHILE LOOP - END LOOP***/
--Abrindo o cursor
open cC1;
/* 1-) Instrução de início do loop
Este loop será executado enquanto a variável vID for menor que 3
*/
WHILE vID < 3 LOOP
dbms_output.put_line("********************************************************");
--2-) Atribuindo o retorno da consulta, às variáveis
fetch cC1
into vID, vNome;
--3-) Escrevendo o valor das variáveis somente...
dbms_output.put_line("ID: " || vID);
dbms_output.put_line("Nome: " || vNome);
--4-) instrução para finalizar o loop
end loop;
--5-)Fechando o cursor para disponibilizar os recursos que estavam sendo utilizados
close cC1;
end PrcTesteCursor_While;
/*#####################################################################
Neste exemplo, "varreremos" o cursor com um laço do tipo FOR – LOOP
#####################################################################*/
procedure PrcTesteCursor_FOR1 As
--Declarando as variáveis que serão manipuladas
vID int;
vNome varchar2(100);
--Criando o cursor que fará um select na tabela de clientes...
cursor cC1 is
SELECT ID, NOME FROM TBLCLIENTE ORDER BY ID;
--1-) declarando a varíavel que servirá como contador
vContador int := 0;
begin
dbms_output.put_line("*****EXEMPLO DE LAÇO USANDO WHILE FOR – LOOP USANDO DUAS CONSTANTES*****");
/* **Exemplo de Laço do tipo FOR – LOOP***/
--Abrindo o cursor
open cC1;
/* 2-) Instrução de início do loop
Este loop será executado enquanto a variável vContador estiver dentro do intervalo de 1 até 3
*/
FOR vContador in 1..3 LOOP
dbms_output.put_line("********************************************************");
--3-) Atribuindo o retorno da consulta, às variáveis
fetch cC1
into vID, vNome;
--4-) escrevendo o valor das variáveis somente...
dbms_output.put_line("ID: " || vID);
dbms_output.put_line("Nome: " || vNome);
--5-) instrução para finalizar o loop
end loop;
--6-)Fechando o cursor para disponibilizar os recursos que estavam sendo utilizados
close cC1;
end PrcTesteCursor_FOR1;
/*#####################################################################
Neste exemplo, "varreremos" o cursor com um laço do tipo FOR – LOOP, com um intervalo
variável
#####################################################################*/
procedure PrcTesteCursor_FOR2 As
--Declarando as variáveis que serão manipuladas
vID int;
vNome varchar2(100);
--Criando o cursor que fará um select na tabela de clientes...
cursor cC1 is
SELECT ID, NOME FROM TBLCLIENTE ORDER BY ID;
--1-) declarando a varíavel que servirá como contador
vContador int := 0;
--2-) declarando as variaveis de limite do range de execução
vMin int := 2;
vMax int := 4;
begin
dbms_output.put_line("*****EXEMPLO DE LAÇO USANDO WHILE FOR – LOOP USANDO DUAS CONSTANTES*****");
/* **Exemplo de Laço do tipo FOR – LOOP***/
--Abrindo o cursor
open cC1;
/* 2-) Instrução de início do loop
Este loop será executado enquanto a variável vContador estiver dentro do intervalo de 2 até 4
*/
FOR vContador in vMin..vMax LOOP
dbms_output.put_line("********************************************************");
--3-) Atribuindo o retorno da consulta, às variáveis
fetch cC1
into vID, vNome;
--4-) escrevendo o valor das variáveis somente...
dbms_output.put_line("ID: " || vID);
dbms_output.put_line("Nome: " || vNome);
--5-) instrução para finalizar o loop
end loop;
--6-)Fechando o cursor para disponibilizar os recursos que estavam sendo utilizados
close cC1;
end PrcTesteCursor_FOR2;
/*#####################################################################
Neste exemplo, "varreremos" o cursor com um laço do tipo FOR – LOOP, com um intervalo
variável e decrescente
#####################################################################*/
procedure PrcTesteCursor_FOR3 As
--Declarando as variáveis que serão manipuladas
vID int;
vNome varchar2(100);
--Criando o cursor que fará um select na tabela de clientes...
cursor cC1 is
SELECT ID, NOME FROM TBLCLIENTE ORDER BY ID ;
--1-) declarando a varíavel que servirá como contador
vContador int := 0;
--2-) declarando as variaveis de limite do range de execução
vMin int := 2;
vMax int := 4;
begin
dbms_output.put_line("*****EXEMPLO DE LAÇO USANDO WHILE FOR – LOOP USANDO DUAS CONSTANTES – e a keyword REVERSE (Veja que o contador foi decrementado!)*****");
/* **Exemplo de Laço do tipo FOR – LOOP***/
--Abrindo o cursor
open cC1;
/* 2-) Instrução de início do loop
Este loop será executado enquanto a variável vContador estiver dentro do intervalo de 4 até 2.
Observe que neste caso usamos a keyword REVERSE, que indica que o contador será decrementado.
*/
FOR vContador in REVERSE vMin .. vMax LOOP
dbms_output.put_line("********************************************************");
dbms_output.put_line("Valor do contador: " || vContador);
--3-) Atribuindo o retorno da consulta, às variáveis
fetch cC1
into vID, vNome;
--4-) escrevendo o valor das variáveis somente...
dbms_output.put_line("ID: " || vID);
dbms_output.put_line("Nome: " || vNome);
--5-) instrução para finalizar o loop
end loop;
--6-)Fechando o cursor para disponibilizar os recursos que estavam sendo utilizados
close cC1;
end PrcTesteCursor_FOR3;
END PKG_EXEMPLOSCURSOR;
Agora, veja abaixo o script que eu utilizei para realizar os testes, e o resultado de cada uma das procedures:
· Procedure pkg_exemploscursor.prctestecursor_loop:
o Script
begin
-- Chamando a procedure
pkg_exemploscursor.prctestecursor_loop;
end;
o Resultado
*****EXEMPLO DE LAÇO USANDO LOOP- END LOOP COM A CONDIÇÃO EXIT- WHEN*****
********************************************************
ID: 2
Nome: Adonirandina
********************************************************
ID: 3
Nome: Rivadaviana
********************************************************
ID: 4
Nome: Carrolindini
********************************************************
ID: 5
Nome: Adalgiso
********************************************************
ID: 6
Nome: Braulinildo
********************************************************
ID: 7
Nome: Rubélinja
********************************************************
· Procedure pkg_exemploscursor.prctestecursor_loop_exit:
o Script
begin
-- Chamando a procedure
pkg_exemploscursor.prctestecursor_loop_exit;
end;
o Resultado
*****EXEMPLO DE LAÇO USANDO LOOP- END LOOP E INTERROMPIDO COM O COMANDO EXIT (QUE DEVE SER USADO SOMENTE EM LOOPS!)*****
********************************************************
ID: 2
Nome: Adonirandina
********************************************************
ID: 3
Nome: Rivadaviana
********************************************************
· Procedure pkg_exemploscursor.prctestecursor_while:
o Script
begin
-- Chamando a procedure
pkg_exemploscursor.prctestecursor_while;
end;
o Resultado
*****EXEMPLO DE LAÇO USANDO WHILE LOOP- END LOOP*****
********************************************************
ID: 2
Nome: Adonirandina
********************************************************
ID: 3
Nome: Rivadaviana
· Procedure pkg_exemploscursor.prctestecursor_for1:
o Script
begin
-- Call the procedure
pkg_exemploscursor.prctestecursor_for1;
end;
o Resultado
*****EXEMPLO DE LAÇO USANDO WHILE FOR – LOOP USANDO DUAS CONSTANTES*****
********************************************************
ID: 2
Nome: Adonirandina
********************************************************
ID: 3
Nome: Rivadaviana
********************************************************
ID: 4
Nome: Carrolindini
· Procedure pkg_exemploscursor.prctestecursor_for2:
o Script
begin
-- Call the procedure
pkg_exemploscursor.prctestecursor_for2;
end;
o Resultado
*****EXEMPLO DE LAÇO USANDO WHILE FOR – LOOP USANDO DUAS CONSTANTES*****
********************************************************
ID: 2
Nome: Adonirandina
********************************************************
ID: 3
Nome: Rivadaviana
********************************************************
ID: 4
Nome: Carrolindini
· Procedure pkg_exemploscursor.prctestecursor_for3:
o Script
begin
-- Call the procedure
pkg_exemploscursor.prctestecursor_for3;
end;
o Resultado
*****EXEMPLO DE LAÇO USANDO WHILE FOR – LOOP USANDO DUAS CONSTANTES – e a keyword REVERSE (Veja que o contador foi decrementado!)*****
********************************************************
Valor do contador: 4
ID: 2
Nome: Adonirandina
********************************************************
Valor do contador: 3
ID: 3
Nome: Rivadaviana
********************************************************
Valor do contador: 2
ID: 4
Nome: Carrolindini
Bom agora que já falamos sobre os tipos de laço, criamos uma package com diversas procedures, executamos cada uma destas procedures e vimos o resultado, chega ao fim este segundo artigo da série sobre os cursores. No próximo artigo onde finalizarei esta série, falarei sobre o tipo REF CURSOR e darei algumas dicas sobre outros objetos que eu acho que podem ser úteis.
Espero que este artigo tenha ajudado! E em caso de dúvidas podem entrar em contato comigo através do e-mail dani@wbsoft.com.br .
Abraços,
Danielle