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