Los bucles anidados son bucles que funcionan dentro de otros bucles. Imagínate una sección de preguntas en una entrevista, donde una pregunta lleva a nuevas preguntas aclaratorias. La lógica de los bucles anidados es así: el bucle externo hace una iteración, y el bucle interno recorre para cada iteración del bucle externo.
Ejemplo: tabla de multiplicar
Vamos a escribir una función que crea una tabla de multiplicar para los números del 1 al 5. Es un ejemplo clásico donde se usan bucles anidados:
CREATE OR REPLACE FUNCTION generate_multiplication_table()
RETURNS VOID AS $$
BEGIN
FOR i IN 1..5 LOOP -- Bucle externo
FOR j IN 1..5 LOOP -- Bucle interno
RAISE NOTICE '% x % = %', i, j, i * j; -- Mostramos el resultado
END LOOP;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- Llamada a la función:
SELECT generate_multiplication_table();
Lógica de funcionamiento:
- El bucle externo toma los valores de
idel 1 al 5. - Para cada valor de
i, el bucle interno toma los valores dejdel 1 al 5. - En cada paso se combinan los valores de
iyjpara calcular el resultado de la multiplicación. - La salida se ve como una mini tabla:
1 x 1 = 1
1 x 2 = 2
...
5 x 5 = 25
Práctica: buscar intersecciones en dos tablas
Ahora vamos a crear un ejemplo más "de la vida real". Imagina que tenemos dos tablas:
students(estudiantes, sus nombres),courses(cursos en los que están inscritos).
Queremos encontrar estudiantes que están inscritos en más de un curso. Usamos bucles anidados:
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;
-- Llamada a la función:
SELECT * FROM find_students_with_multiple_courses();
Recursión
La recursión es cuando una función se llama a sí misma. Es como si le pides a un colega que te explique SQL y te dice que leas la documentación, que a su vez te manda a esta misma lección... No confundas recursión con un bucle infinito. La recursión siempre tiene una "condición de parada" (el punto donde la función deja de llamarse a sí misma).
Ejemplo: calcular el factorial de un número
El factorial de un número n es el producto de todos los números del 1 al n. Por ejemplo, el factorial de 5 (se escribe 5!) es 5 * 4 * 3 * 2 * 1 = 120. Así se puede hacer con recursión:
CREATE OR REPLACE FUNCTION calculate_factorial(n INTEGER)
RETURNS INTEGER AS $$
BEGIN
-- Condición de parada: el factorial de 0 o 1 es 1
IF n = 0 OR n = 1 THEN
RETURN 1;
END IF;
-- Llamada recursiva de la función
RETURN n * calculate_factorial(n - 1);
END;
$$ LANGUAGE plpgsql;
-- Llamada a la función:
SELECT calculate_factorial(5); -- Resultado: 120
Lógica de funcionamiento:
- Si
nes 0 o 1, devolvemos 1. - Si
n > 1, la función se llama a sí misma con el argumenton - 1y multiplica ese valor porn. - Así, las llamadas se "acumulan" y luego se resuelven en una sola dirección.
Ejemplo práctico: números de Fibonacci
Los números de Fibonacci son una secuencia donde cada número es la suma de los dos anteriores. La secuencia empieza así: 0, 1, 1, 2, 3, 5, 8....
Vamos a escribir una función para calcular el n-ésimo número de la secuencia:
CREATE OR REPLACE FUNCTION fibonacci(n INTEGER)
RETURNS INTEGER AS $$
BEGIN
-- Condición de parada: los dos primeros números son conocidos
IF n = 0 THEN
RETURN 0;
ELSIF n = 1 THEN
RETURN 1;
END IF;
-- Llamada recursiva de la función
RETURN fibonacci(n - 1) + fibonacci(n - 2);
END;
$$ LANGUAGE plpgsql;
-- Llamada a la función:
SELECT fibonacci(6); -- Resultado: 8
¿Cuándo usar bucles anidados y recursión?
Los bucles anidados van bien para trabajar con tablas:
- Comparar valores entre dos tablas.
- Construir combinaciones complejas de datos.
La recursión es mejor para:
- Calcular secuencias (por ejemplo, factoriales, Fibonacci).
- Trabajar con estructuras jerárquicas (por ejemplo, árbol de categorías de productos).
Errores típicos
Los bucles anidados a veces son "caros" en cuanto a rendimiento, sobre todo si trabajas con tablas grandes. Úsalos solo cuando no puedas conseguir el resultado con SQL normal.
Cuando uses recursión, asegúrate de tener una "condición de parada" clara. Si no, tendrás una llamada infinita de la función y, probablemente, un error de desbordamiento de pila.
Las construcciones anidadas complejas pueden dificultar la depuración. Ayúdate con RAISE NOTICE para mostrar resultados intermedios.
GO TO FULL VERSION