Banco de Dados - OracleFeed de artigos deste autor

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 Monteiro



Neste 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

Danielle Monteiro

Danielle Monteiro - Formada pela FATEC-SP, MCP (Microsoft Certified Professional), atua há 7 anos na área de desenvolvimento de sistemas.
Com grande experiência em VB.NET, C#, SQL Server (em diversas versões), Reporting Services 2005 e Oracle (também em diversas versões) é Analista de Sistemas da IT Group.