ITERATE
ITERATE salta el resto del cuerpo del bucle y comienza la siguiente iteración. Es el equivalente a continue en lenguajes como JavaScript, Java o C. Solo se puede usar dentro de LOOP, WHILE y REPEAT.
Mientras que LEAVE termina el bucle completamente, ITERATE lo que hace es decir "esta iteración ya no me interesa, pasa a la siguiente". Es útil cuando necesitas filtrar elementos dentro de un bucle: en lugar de envolver todo el código en un IF, usas ITERATE para saltar los elementos que no cumplen tus criterios y mantienes el código principal sin anidamiento adicional.
Sintaxis
ITERATE etiqueta;Al igual que LEAVE, necesita una etiqueta que identifique el bucle al que se aplica. No se puede usar fuera de un bucle ni con bloques BEGIN...END (a diferencia de LEAVE, que sí puede salir de bloques).
Ejemplo básico: saltar números pares
El caso más simple de ITERATE es filtrar elementos en un bucle. En lugar de procesar todos los números y usar un IF para decidir si imprimirlos, ITERATE salta directamente los que no nos interesan:
DELIMITER //
CREATE PROCEDURE solo_impares(IN limite INT)
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE resultado VARCHAR(500) DEFAULT '';
numeros: LOOP
SET i = i + 1;
IF i > limite THEN
LEAVE numeros;
END IF;
-- Saltar números pares
IF i MOD 2 = 0 THEN
ITERATE numeros;
END IF;
SET resultado = CONCAT(resultado, i, ' ');
END LOOP numeros;
SELECT TRIM(resultado) AS impares;
END //
DELIMITER ;CALL solo_impares(10);| impares |
|---|
| 1 3 5 7 9 |
Cuando i es par, ITERATE salta directamente al inicio del bucle (incrementando primero i en la siguiente iteración). El CONCAT después del ITERATE nunca se ejecuta para los números pares. Esto produce un código más limpio que la alternativa con IF: en lugar de IF i MOD 2 != 0 THEN SET resultado = CONCAT(...); END IF, el ITERATE invierte la lógica y elimina un nivel de anidamiento.
Es importante notar que el incremento de i está antes del ITERATE. Si estuviera después, ITERATE lo saltaría y crearíamos un bucle infinito (i nunca cambiaría). Este es el error más común al usar ITERATE: asegúrate de que la lógica que avanza el bucle se ejecute antes de cualquier ITERATE.
ITERATE en WHILE
ITERATE funciona en cualquier tipo de bucle. En un WHILE, salta al inicio del bucle donde se reevalúa la condición. Esto es útil para filtrar filas de un cursor sin necesidad de anidar toda la lógica de procesamiento dentro de un IF:
DELIMITER //
CREATE PROCEDURE productos_caros_con_stock()
BEGIN
DECLARE v_nombre VARCHAR(100);
DECLARE v_precio DECIMAL(10,2);
DECLARE v_stock INT;
DECLARE v_done INT DEFAULT FALSE;
DECLARE v_total INT DEFAULT 0;
DECLARE cur CURSOR FOR
SELECT nombre, precio, stock FROM productos WHERE activo = TRUE ORDER BY precio DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
DROP TEMPORARY TABLE IF EXISTS tmp_resultado;
CREATE TEMPORARY TABLE tmp_resultado (
nombre VARCHAR(100),
precio DECIMAL(10,2),
stock INT
);
OPEN cur;
filtrar: WHILE NOT v_done DO
FETCH cur INTO v_nombre, v_precio, v_stock;
IF v_done THEN
LEAVE filtrar;
END IF;
-- Saltar productos baratos
IF v_precio < 500 THEN
ITERATE filtrar;
END IF;
-- Saltar productos sin stock
IF v_stock = 0 THEN
ITERATE filtrar;
END IF;
INSERT INTO tmp_resultado VALUES (v_nombre, v_precio, v_stock);
SET v_total = v_total + 1;
END WHILE filtrar;
CLOSE cur;
SELECT * FROM tmp_resultado;
SELECT v_total AS total_encontrados;
DROP TEMPORARY TABLE tmp_resultado;
END //
DELIMITER ;CALL productos_caros_con_stock();| nombre | precio | stock |
|---|---|---|
| ASUS ROG Zephyrus | 1899.99 | 12 |
| Lenovo ThinkPad X1 | 1549.00 | 18 |
| MacBook Air M3 | 1399.00 | 25 |
| iPhone 15 Pro | 1299.99 | 45 |
| Samsung Galaxy S24 | 899.99 | 62 |
| Samsung TV QLED 55" | 749.00 | 20 |
| Google Pixel 8 | 699.00 | 38 |
| Xiaomi 14 | 599.99 | 80 |
| Sofá 3 plazas | 599.00 | 8 |
Cada ITERATE actúa como un "guardia" que filtra elementos no deseados. El código de procesamiento (INSERT, incremento del contador) solo se ejecuta para las filas que pasan todos los filtros. Sin ITERATE, necesitarías IF v_precio >= 500 AND v_stock > 0 THEN ... END IF, lo cual funciona igual pero con más anidamiento. Con muchos filtros, la diferencia de legibilidad se hace notable.
FizzBuzz con ITERATE
FizzBuzz es un ejercicio clásico de programación que se adapta muy bien para demostrar ITERATE. El truco es verificar las condiciones de mayor a menor prioridad y usar ITERATE para saltar al siguiente número una vez que se ha clasificado el actual:
DELIMITER //
CREATE PROCEDURE fizzbuzz(IN limite INT)
BEGIN
DECLARE i INT DEFAULT 0;
DROP TEMPORARY TABLE IF EXISTS tmp_fizzbuzz;
CREATE TEMPORARY TABLE tmp_fizzbuzz (
numero INT,
valor VARCHAR(10)
);
fb: LOOP
SET i = i + 1;
IF i > limite THEN
LEAVE fb;
END IF;
IF i MOD 15 = 0 THEN
INSERT INTO tmp_fizzbuzz VALUES (i, 'FizzBuzz');
ITERATE fb;
END IF;
IF i MOD 3 = 0 THEN
INSERT INTO tmp_fizzbuzz VALUES (i, 'Fizz');
ITERATE fb;
END IF;
IF i MOD 5 = 0 THEN
INSERT INTO tmp_fizzbuzz VALUES (i, 'Buzz');
ITERATE fb;
END IF;
INSERT INTO tmp_fizzbuzz VALUES (i, CAST(i AS CHAR));
END LOOP fb;
SELECT * FROM tmp_fizzbuzz;
DROP TEMPORARY TABLE tmp_fizzbuzz;
END //
DELIMITER ;CALL fizzbuzz(15);| numero | valor |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | Fizz |
| 4 | 4 |
| 5 | Buzz |
| 6 | Fizz |
| 7 | 7 |
| 8 | 8 |
| 9 | Fizz |
| 10 | Buzz |
| 11 | 11 |
| 12 | Fizz |
| 13 | 13 |
| 14 | 14 |
| 15 | FizzBuzz |
Cada ITERATE actúa como un "ya clasificado, pasa al siguiente". El orden importa: i MOD 15 (FizzBuzz) debe ir antes que i MOD 3 (Fizz) y i MOD 5 (Buzz), porque 15 es múltiplo de ambos. Si no se cumple ninguna condición, se ejecuta el INSERT final con el número tal cual.
LEAVE vs ITERATE
Ambas sentencias controlan el flujo dentro de un bucle, pero con efectos opuestos:
| Sentencia | Efecto | Equivalente | Cuándo usar |
|---|---|---|---|
| LEAVE | Sale del bucle completamente | break | Terminación anticipada, dato encontrado |
| ITERATE | Salta a la siguiente iteración | continue | Filtrar elementos, saltar casos inválidos |
Un patrón habitual es usar ambas en el mismo bucle: LEAVE para la terminación y ITERATE para el filtrado.
Cuándo usar ITERATE vs IF
ITERATE y un IF envolvente producen el mismo resultado, pero la legibilidad difiere. Compara estas dos formas equivalentes:
Con ITERATE (filtro negativo, sin anidamiento):
IF v_precio < 500 THEN ITERATE bucle; END IF;
IF v_stock = 0 THEN ITERATE bucle; END IF;
-- código principal aquí, sin anidamientoCon IF (filtro positivo, con anidamiento):
IF v_precio >= 500 AND v_stock > 0 THEN
-- código principal aquí, anidado un nivel
END IF;Cuando hay 2 o 3 condiciones, la diferencia es menor. Pero cuando hay 5 o más filtros, ITERATE mantiene el código plano mientras que IF produce un anidamiento profundo.
Limpieza
DROP PROCEDURE IF EXISTS solo_impares;
DROP PROCEDURE IF EXISTS productos_caros_con_stock;
DROP PROCEDURE IF EXISTS fizzbuzz;En el siguiente artículo veremos los cursores, que permiten recorrer un conjunto de resultados fila por fila dentro de un procedimiento.
Escrito por Eduardo Lázaro
