Loops aninhados são loops que rodam dentro de outros loops. Imagina uma entrevista de emprego, quando uma pergunta leva a outras perguntas mais detalhadas. A lógica dos loops aninhados é assim: o loop externo faz uma iteração, e o loop interno faz várias passadas pra cada iteração do externo.
Exemplo: tabela de multiplicação
Bora criar uma função que gera a tabela de multiplicação pros números de 1 a 5. Esse é o exemplo clássico de uso de loops aninhados:
CREATE OR REPLACE FUNCTION generate_multiplication_table()
RETURNS VOID AS $$
BEGIN
FOR i IN 1..5 LOOP -- Loop externo
FOR j IN 1..5 LOOP -- Loop interno
RAISE NOTICE '% x % = %', i, j, i * j; -- Logando o resultado
END LOOP;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- Chamando a função:
SELECT generate_multiplication_table();
Lógica de funcionamento:
- O loop externo pega os valores de
ide 1 a 5. - Pra cada valor de
i, o loop interno pega os valores dejde 1 a 5. - Em cada passo, os valores de
iejsão combinados pra calcular o resultado da multiplicação. - A saída fica tipo uma mini-tabela:
1 x 1 = 1
1 x 2 = 2
...
5 x 5 = 25
Prática: buscando interseções em duas tabelas
Agora bora pra um exemplo mais "vida real". Imagina que a gente tem duas tabelas:
students(alunos, os nomes deles),courses(cursos nos quais eles estão matriculados).
A gente quer achar os alunos que estão em mais de um curso. Vamos usar loops aninhados:
CREATE OR REPLACE FUNCTION find_students_with_multiple_courses()
RETURNS TABLE(student_name TEXT, course_name TEXT) AS $$
BEGIN
FOR student IN SELECT DISTINCT student_name FROM students LOOP
FOR course IN SELECT DISTINCT course_name FROM courses WHERE student_id = student.student_id LOOP
RETURN QUERY SELECT student.student_name, course.course_name;
END LOOP;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- Chamando a função:
SELECT * FROM find_students_with_multiple_courses();
Recursão
Recursão é quando uma função chama ela mesma. É tipo pedir pra um amigo te explicar SQL e ele manda você ler a documentação, que manda você voltar pra essa mesma aula... Não confunde recursão com loop infinito. Recursão sempre tem uma "condição de parada" (o ponto onde a função para de se chamar).
Exemplo: calculando o fatorial de um número
O fatorial de um número n é o produto de todos os números de 1 até n. Por exemplo, o fatorial de 5 (escrito 5!) é 5 * 4 * 3 * 2 * 1 = 120. Olha como dá pra fazer isso com recursão:
CREATE OR REPLACE FUNCTION calculate_factorial(n INTEGER)
RETURNS INTEGER AS $$
BEGIN
-- Condição de parada: fatorial de 0 ou 1 é 1
IF n = 0 OR n = 1 THEN
RETURN 1;
END IF;
-- Chamada recursiva da função
RETURN n * calculate_factorial(n - 1);
END;
$$ LANGUAGE plpgsql;
-- Chamando a função:
SELECT calculate_factorial(5); -- Resultado: 120
Lógica de funcionamento:
- Se
nfor 0 ou 1, retorna 1. - Se
n > 1, a função chama ela mesma com o argumenton - 1e multiplica esse valor porn. - Assim, as chamadas vão "acumulando" e depois desenrolam tudo de uma vez.
Exemplo prático: números de Fibonacci
Os números de Fibonacci são uma sequência onde cada número é a soma dos dois anteriores. A sequência começa assim: 0, 1, 1, 2, 3, 5, 8....
Bora criar uma função pra calcular o n-ésimo número da sequência:
CREATE OR REPLACE FUNCTION fibonacci(n INTEGER)
RETURNS INTEGER AS $$
BEGIN
-- Condição de parada: os dois primeiros números já são conhecidos
IF n = 0 THEN
RETURN 0;
ELSIF n = 1 THEN
RETURN 1;
END IF;
-- Chamada recursiva da função
RETURN fibonacci(n - 1) + fibonacci(n - 2);
END;
$$ LANGUAGE plpgsql;
-- Chamando a função:
SELECT fibonacci(6); -- Resultado: 8
Quando usar loops aninhados e recursão?
Loops aninhados são ótimos pra trabalhar com tabelas:
- Comparar valores entre duas tabelas.
- Montar combinações de dados mais complexas.
Recursão é melhor pra:
- Calcular sequências (tipo fatorial, Fibonacci).
- Trabalhar com estruturas hierárquicas (tipo árvore de categorias de produtos).
Erros comuns
Loops aninhados às vezes são "caros" em performance, principalmente com tabelas grandes. Usa só quando não dá pra resolver com SQL normal.
Quando usar recursão, garante que você tem uma "condição de parada" clara. Sem isso, vai rolar chamada infinita da função e provavelmente erro de stack overflow.
Estruturas aninhadas muito complexas podem dificultar o debug. Se ajuda usando RAISE NOTICE pra mostrar resultados intermediários.
GO TO FULL VERSION