Hoje vamos mergulhar fundo no fascinante mundo dos Cursor FOR Loops em Oracle PL/SQL. Esta é uma ferramenta poderosa que simplifica muito o trabalho com cursores. Vamos explorar todos os aspectos deste recurso, com exemplos práticos e insights valiosos! Se você quer executar os exemplos, certifique-se de que você criou os objetos conforme mostrado nesse outro artigo sobre cursores implícitos.
Introdução aos Cursor FOR Loops
Antes de entrarmos nos detalhes, vamos entender o que são Cursor FOR Loops e por que eles são tão úteis.
Um Cursor FOR Loop é uma estrutura de controle em PL/SQL que combina a declaração de um cursor com um loop FOR. Esta combinação nos permite processar todas as linhas retornadas por um cursor de forma mais simples e eficiente do que usando um loop explícito.
Vantagens dos Cursor FOR Loops
- Simplicidade: Reduz a quantidade de código necessário para processar um cursor.
- Automação: O PL/SQL cuida automaticamente da abertura, busca e fechamento do cursor.
- Eficiência: Otimiza o uso de recursos do banco de dados.
- Legibilidade: Torna o código mais fácil de ler e entender.
Sintaxe Básica
A sintaxe básica de um Cursor FOR Loop é a seguinte:
1 2 3 |
FOR record_variable IN cursor_name LOOP -- Processamento das linhas do cursor END LOOP; |
Ou, para um cursor inline:
1 2 3 |
FOR record_variable IN (SELECT statement) LOOP -- Processamento das linhas do cursor END LOOP; |
Exemplo Prático: Processando Informações de Cursos
Vamos ver um exemplo prático usando a tabela de cursos:
1 2 3 4 5 6 7 8 9 10 |
BEGIN FOR curso_rec IN (SELECT numero_curso, descricao, creditos FROM curso WHERE departamento = 'CS' ORDER BY numero_curso) LOOP DBMS_OUTPUT.PUT_LINE('Curso: ' || curso_rec.numero_curso || ' - ' || curso_rec.descricao || ' (' || curso_rec.creditos || ' créditos)'); END LOOP; END; |
Neste exemplo:
- Usamos um cursor inline para selecionar cursos do departamento de Ciência da Computação (CS).
- O PL/SQL cria automaticamente uma variável de registro
curso_rec
com a estrutura do resultado do SELECT. - O loop processa cada linha retornada pelo cursor, imprimindo as informações do curso.
Cursor FOR Loops com Cursores Explícitos
Podemos também usar Cursor FOR Loops com cursores explícitos. Vejamos um exemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
DECLARE CURSOR c_instrutores IS SELECT id_instrutor, primeiro_nome, sobrenome, salario FROM instrutor WHERE departamento = 'MATH' ORDER BY salario DESC; BEGIN FOR instrutor_rec IN c_instrutores LOOP DBMS_OUTPUT.PUT_LINE('Instrutor: ' || instrutor_rec.primeiro_nome || ' ' || instrutor_rec.sobrenome || ' - Salário: $' || TO_CHAR(instrutor_rec.salario, '999,999.00')); END LOOP; END; |
Neste exemplo:
- Declaramos um cursor explícito
c_instrutores
. - Usamos este cursor em um FOR Loop.
- O PL/SQL gerencia automaticamente a abertura, busca e fechamento do cursor.
Cursor FOR Loops com Parâmetros
Podemos tornar nossos Cursor FOR Loops mais flexíveis usando parâmetros. Veja este exemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
DECLARE CURSOR c_estudantes(p_curso_id NUMBER) IS SELECT s.id_estudante, s.primeiro_nome, s.sobrenome, e.nota FROM estudante s JOIN inscricao e ON s.id_estudante = e.id_estudante WHERE e.id_curso = p_curso_id ORDER BY e.nota DESC; v_curso_id NUMBER := 101; -- ID do curso que queremos analisar BEGIN DBMS_OUTPUT.PUT_LINE('Estudantes do Curso ' || v_curso_id || ':'); FOR estudante_rec IN c_estudantes(v_curso_id) LOOP DBMS_OUTPUT.PUT_LINE(estudante_rec.primeiro_nome || ' ' || estudante_rec.sobrenome || ' - Nota: ' || estudante_rec.nota); END LOOP; END; |
Neste exemplo:
- Definimos um cursor com um parâmetro
p_curso_id
. - Usamos este cursor parametrizado em um FOR Loop, passando o ID do curso desejado.
Características Especiais dos Cursor FOR Loops
- Variável de Registro Implícita:
- O PL/SQL cria automaticamente uma variável de registro baseada na estrutura do cursor.
- Esta variável só existe dentro do loop.
- Gerenciamento Automático do Cursor:
- O cursor é aberto implicitamente no início do loop.
- As linhas são buscadas automaticamente a cada iteração.
- O cursor é fechado implicitamente ao final do loop.
- Sem Necessidade de EXIT WHEN:
- O loop termina automaticamente quando todas as linhas forem processadas.
- Otimização de Desempenho:
- O Oracle otimiza internamente os Cursor FOR Loops para melhor desempenho.
Limitações e Considerações
- Não é possível usar FETCH explícito dentro de um Cursor FOR Loop.
- Não temos acesso direto aos atributos do cursor (como %FOUND, %NOTFOUND, %ROWCOUNT) dentro do loop.
- Não podemos modificar a variável de registro do loop (ela é tratada como constante).
Exemplo Avançado: Cursor FOR Loop com Exception Handling
Vamos ver um exemplo mais complexo que inclui tratamento de exceções:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
DECLARE CURSOR c_atualizacao_salario IS SELECT id_instrutor, salario, departamento FROM instrutor WHERE data_contratacao < ADD_MONTHS(SYSDATE, -60) -- Instrutores com mais de 5 anos FOR UPDATE OF salario NOWAIT; v_aumento NUMBER := 1.05; -- 5% de aumento v_contagem_atualizados NUMBER := 0; v_contagem_erros NUMBER := 0; BEGIN FOR instr_rec IN c_atualizacao_salario LOOP BEGIN UPDATE instrutor SET salario = instr_rec.salario * v_aumento WHERE CURRENT OF c_atualizacao_salario; v_contagem_atualizados := v_contagem_atualizados + 1; DBMS_OUTPUT.PUT_LINE('Atualizado: Instrutor ID ' || instr_rec.id_instrutor || ' - Novo salário: $' || TO_CHAR(instr_rec.salario * v_aumento, '999,999.00')); EXCEPTION WHEN OTHERS THEN v_contagem_erros := v_contagem_erros + 1; DBMS_OUTPUT.PUT_LINE('Erro ao atualizar Instrutor ID ' || instr_rec.id_instrutor || ': ' || SQLERRM); END; END LOOP; DBMS_OUTPUT.PUT_LINE('Resumo: ' || v_contagem_atualizados || ' instrutores atualizados, ' || v_contagem_erros || ' erros encontrados.'); COMMIT; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Erro geral: ' || SQLERRM); ROLLBACK; END; |
Neste exemplo avançado:
- Usamos um cursor FOR UPDATE para atualizar salários de instrutores.
- Implementamos tratamento de exceções para cada atualização individual.
- Mantemos contadores para atualizações bem-sucedidas e erros.
- Usamos COMMIT para confirmar as alterações ou ROLLBACK em caso de erro geral.
Dicas e Melhores Práticas
- Use Cursor FOR Loops sempre que possível para simplificar seu código.
- Para cursores simples, prefira a sintaxe inline para maior concisão.
- Use cursores explícitos quando precisar reutilizar o mesmo cursor em diferentes partes do código.
- Aproveite a otimização automática do Oracle para Cursor FOR Loops.
- Lembre-se de que não pode modificar a variável de registro dentro do loop.
Conclusão
Os Cursor FOR Loops são uma ferramenta poderosa e eficiente no arsenal do desenvolvedor PL/SQL. Eles simplificam significativamente o processamento de conjuntos de resultados, tornando o código mais limpo, mais fácil de entender e menos propenso a erros.
Pontos-chave para lembrar:
- Cursor FOR Loops combinam declaração de cursor e loop em uma única estrutura.
- Eles automatizam a abertura, busca e fechamento do cursor.
- Podem ser usados com cursores inline ou explícitos.
- São otimizados pelo Oracle para melhor desempenho.
- Têm limitações, como a impossibilidade de modificar a variável de registro.