GPO ( Grupo de Profissionais Oracle )
A maior comunidade Oracle do Brasil !

Controle Iterativo de Loops Aninhados

A linguagem de programação PL/SQL nos fornece uma opção de aninhar loops em vários níveis, ou seja, podemos aninhar FOR, WHILE e Loops básicos um dentro do outro.

Exemplo 01:

BEGIN
  FOR v_loop_externo IN 1..3 LOOP
    FOR v_loop_interno IN REVERSE 1..5 LOOP
      DBMS_OUTPUT.PUT_LINE('O loop externo é:'||v_loop_externo||
            ' e o loop interno é: '||v_loop_interno);
    END LOOP;
  END LOOP;
END;

O exemplo acima mostra um Loop aninhado utilizando a instrução “For Loop“:

Passo 01:

O laço é limitado em 3 iterações. Uma das características desse Loop é justamente o controle de iterações quando se sabe o numero de iterações que são necessárias.

Passo 02:

O segundo laço interno é limitado em 5 iterações, controlando assim as iterações. Há a palavra chave “REVERSE” que tem a função de reverter à ordem de ascendente para decrescente.

Passo 03:

Usa-se o procedimento “PUT_LINE” nativo do banco de dados Oracle contido no pacote “DBMS_OUTPUT” para imprimir uma mensagem a cada iteração do loop aninhado.

Escopo de variáveis

É importante ressaltar o uso das variais em seu devido escopo.

No “exemplo 01” não se pode utilizar a variável “v_loop_interno” declarada implicitamente pelo comando “For Loop” no escopo “For Loop” externo, pois a variável não é visível.

Exemplo 02:

SET SERVEROUTPUT ON

BEGIN
  <<loop_externo>>
  FOR v_igual IN 1..3 LOOP
    <<loop_interno>>
    FOR v_igual IN REVERSE 1..5 LOOP
      DBMS_OUTPUT.PUT_LINE('O loop externo é:'||loop_externo.v_igual||
                           ' e o loop interno é: '||loop_interno.v_igual);
    END LOOP;
  END LOOP;
END;

No ”exemplo 02”, há a variável “v_igual” declarada implicitamente, com o mesmo nome em dois escopos diferentes, rotulado o “For Loop” externo e interno.

Para chamar a variável externo no escopo interno, pode se utilizar “loop_externo.v_igual” (nome do rótulo ponto nome da variável).

Ao realizar algumas alterações no “exemplo 01”, pode ser criado uma tabuada em PL/SQL.

Exemplo 03:

SET SERVEROUTPUT ON

BEGIN
  FOR v_loop_externo IN 2..2 LOOP
    FOR v_loop_interno IN 1..10 LOOP
      DBMS_OUTPUT.PUT_LINE(v_loop_externo||' x '||v_loop_interno|| 
                           ' = '||v_loop_externo*v_loop_interno);
    END LOOP;
  END LOOP;
END;
/

Quando o código acima é executado no prompt SQLPLUS, ele produz o seguinte resultado:

2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
2 x 4 = 8
2 x 5 = 10
2 x 6 = 12
2 x 7 = 14
2 x 8 = 16
2 x 9 = 18
2 x 10 = 20

O exemplo acima mostra um “For Loop” aninhado utilizado para criar a tabuada do 2.

Modifica-se o “For Loop” externo para 1 iteração e o “For loop” interno para 10 iterações e retira a palavra chave “REVERSE”, tornando a iteração ascendente. Também se pode altera o procedimento que imprime para mostrar as variáveis externa/interna e realizar o calculo de multiplicação.

No “exemplo 04” contém a palavra chave “EXIT WHEN” em um Loop Básico aninhado.

Exemplo 04:

DECLARE
  v_externo    CHAR(3) := ‘NAO’;
  v_interno    CHAR(3) := ‘NAO’;

BEGIN
  LOOP –- loop externo
    ...
    LOOP –- loop interno
      ...
      ... – sair do loop interno para o externo
      EXIT WHEN v_interno = ‘SIM’;
      ...
    END LOOP;
  ...
  EXIT WHEN v_externo = ‘SIM’;
  ...
  END LOOP;
END;

Se for necessário executar o comando sair do loop interno e externo ao mesmo tempo, qual seria a alternativa para isso?

Rótulos!

Pode-se usar rótulo em PL/SQL, quando rotulado um Loop usa-se o comando EXIT (sair) para a instrução Loop rotulada, vejamos o exemplo a seguir:

Exemplo 05:

DECLARE
  v_externo    CHAR(3) := ‘NAO’;
  v_interno    CHAR(3) := ‘NAO’;

BEGIN
  <<loop_externo>>
   LOOP –- loop externo
     ...
     <<loop_interno>>
     LOOP –- loop interno
       EXIT loop_externo WHEN ... -– Sair de ambos os loops
       EXIT WHEN v_interno = ‘SIM’;
       ...
     END LOOP;
   ...
   EXIT WHEN v_externo = ‘SIM’;
   ...
   END LOOP;
END;

Rótulo de Loop

Os nomes dos rótulos seguem as mesmas regras que outros identificadores. Um rótulo é colocado antes de uma instrução, ambos na mesma linha ou em outra linha separada, usando os delimitadores de etiquetas (<< rótulo >>). Se o laço está rotulado, o nome do rótulo pode, opcionalmente, ser incluído após o término da declaração LOOP para maior clareza.

Exemplo 06:

…BEGIN
  <<loop_externo>>
  LOOP
    v_contador := v_contador+1;
    EXIT WHEN v_contador>10;
    <<loop_interno>>
    LOOP
      ...
      EXIT loop_externo WHEN v_externo = 'SIM';
      -- sair de ambos os loops
      EXIT WHEN v_interno = 'SIM';
      -- sair somente do loop interno
      ...
    END LOOP loop_interno;
  ...
  END LOOP loop_externo;
END;

No “exemplo 06“ há dois Loops aninhados e rotulados <<loop_externo>> e <<loop_interno>>. Observa que no término dos Loops também estão rotulados, mas sem a necessidade das etiquetas << >>, como dito é opcional e ajuda na organização do código.

Finalmente, o programa a seguir utiliza um Loop básico aninhado para encontrar os números primos de 2 a 100:

SET SERVEROUTPUT ON

DECLARE
   i number(3);
   j number(3);
BEGIN
   i := 2;
   LOOP
      j:= 2;
      LOOP
         exit WHEN ((mod(i, j) = 0) or (j = i));
         j := j +1;
      END LOOP;
   IF (j = i ) THEN
      dbms_output.put_line(i || ' é primo');
   END IF;
   i := i + 1;
   exit WHEN i = 100;
   END LOOP;
END;
/

Quando o código acima é executado no prompt SQLPLUS, ele produz o seguinte resultado:

2 é primo
3 é primo
5 é primo
7 é primo
11 é primo
13 é primo
17 é primo
19 é primo
23 é primo
29 é primo
31 é primo
37 é primo
...
...
97 é primo

Referências

http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/controlstatements.htm#LNPLS410

http://www.tutorialspoint.com/plsql/plsql_nested_loops.htm

Enjoy

Share

You may also like...

Deixe um comentário

O seu endereço de e-mail não será publicado.