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

Diogo Alves, formado em Análise e Desenvolvimento de Sistemas, Pós Graduado em Engenharia de Software, é especialista em Banco de Dados Oracle com sólidos conhecimentos em SQL e PL/SQL; trabalha com Oracle há 8 anos, é certificado com OCE em SQL, OCA e OCP PL/SQL. Atualmente atua com desenvolvimento de aplicações PL/SQL no setor previdenciário do Estado de São Paulo, na empresa Atlantic Solutions, Localizada em Barueri/SP.