CodeGym /Cursos /SQL SELF /Bucles anidados y recursión

Bucles anidados y recursión

SQL SELF
Nivel 51 , Lección 3
Disponible

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:

  1. El bucle externo toma los valores de i del 1 al 5.
  2. Para cada valor de i, el bucle interno toma los valores de j del 1 al 5.
  3. En cada paso se combinan los valores de i y j para calcular el resultado de la multiplicación.
  4. 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:

  1. Si n es 0 o 1, devolvemos 1.
  2. Si n > 1, la función se llama a sí misma con el argumento n - 1 y multiplica ese valor por n.
  3. 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?

  1. Los bucles anidados van bien para trabajar con tablas:

    • Comparar valores entre dos tablas.
    • Construir combinaciones complejas de datos.
  2. 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.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION