LOOP

LOOP ejecuta un bloque de sentencias repetidamente hasta que se usa LEAVE para salir del bucle. Es el bucle más básico de MySQL y requiere una condición de salida explícita para evitar un bucle infinito.

Sintaxis

[etiqueta:] LOOP
    sentencias;
    IF condicion THEN
        LEAVE etiqueta;
    END IF;
END LOOP [etiqueta];

La etiqueta es necesaria para que LEAVE identifique de qué bucle salir.

Ejemplo básico

DELIMITER //
 
CREATE PROCEDURE contar_hasta(IN limite INT)
BEGIN
    DECLARE contador INT DEFAULT 1;
    DECLARE resultado VARCHAR(500) DEFAULT '';
 
    bucle: LOOP
        IF contador > limite THEN
            LEAVE bucle;
        END IF;
 
        SET resultado = CONCAT(resultado, contador, ' ');
        SET contador = contador + 1;
    END LOOP bucle;
 
    SELECT TRIM(resultado) AS numeros;
END //
 
DELIMITER ;
CALL contar_hasta(5);
numeros
1 2 3 4 5

Generar datos con LOOP

DELIMITER //
 
CREATE PROCEDURE generar_series(IN inicio INT, IN fin INT, IN paso INT)
BEGIN
    DECLARE i INT;
 
    DROP TEMPORARY TABLE IF EXISTS tmp_series;
    CREATE TEMPORARY TABLE tmp_series (valor INT);
 
    SET i = inicio;
 
    insertar: LOOP
        IF i > fin THEN
            LEAVE insertar;
        END IF;
 
        INSERT INTO tmp_series VALUES (i);
        SET i = i + paso;
    END LOOP insertar;
 
    SELECT * FROM tmp_series;
    DROP TEMPORARY TABLE tmp_series;
END //
 
DELIMITER ;
CALL generar_series(10, 50, 10);
valor
10
20
30
40
50

LOOP con procesamiento de datos

DELIMITER //
 
CREATE PROCEDURE ajustar_precios(IN porcentaje DECIMAL(5,2))
BEGIN
    DECLARE v_id INT;
    DECLARE v_precio DECIMAL(10,2);
    DECLARE v_nuevo DECIMAL(10,2);
    DECLARE v_done INT DEFAULT FALSE;
    DECLARE v_contador INT DEFAULT 0;
 
    DECLARE cur CURSOR FOR
        SELECT id, precio FROM productos WHERE precio > 1000 AND activo = TRUE;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
 
    OPEN cur;
 
    leer: LOOP
        FETCH cur INTO v_id, v_precio;
 
        IF v_done THEN
            LEAVE leer;
        END IF;
 
        SET v_nuevo = v_precio * (1 + porcentaje / 100);
        -- En producción: UPDATE productos SET precio = v_nuevo WHERE id = v_id;
        SET v_contador = v_contador + 1;
    END LOOP leer;
 
    CLOSE cur;
 
    SELECT v_contador AS productos_afectados;
END //
 
DELIMITER ;
CALL ajustar_precios(5.00);
productos_afectados
4

Bucle infinito sin LEAVE

Sin LEAVE, el bucle se ejecuta indefinidamente. MySQL tiene un límite de tiempo de ejecución que eventualmente lo detendrá:

-- NUNCA hacer esto:
-- mi_loop: LOOP
--     SELECT 1;  -- Bucle infinito
-- END LOOP mi_loop;

Siempre incluye una condición de salida con LEAVE.

LOOP vs otros bucles

BucleCondiciónEvaluaciónMínimo de ejecuciones
LOOPExplícita con LEAVEDentro del cuerpo0 o más
WHILEEn la cabeceraAntes de cada iteración0
REPEATEn el pieDespués de cada iteración1

Limpieza

DROP PROCEDURE IF EXISTS contar_hasta;
DROP PROCEDURE IF EXISTS generar_series;
DROP PROCEDURE IF EXISTS ajustar_precios;

En el siguiente artículo veremos el bucle WHILE, que evalúa la condición antes de cada iteración.

Escrito por Eduardo Lázaro