MySQL WHILE MySQL · Conditional Statements · WHILE

MySQL WHILE Loop

Master the MySQL WHILE loop — pre-test loop where the condition is checked before each iteration, body may run zero times. Covers counter loops, accumulator patterns, early exit with LEAVE, and the WHILE vs REPEAT vs LOOP comparison for choosing the right tool.

The WHILE loop repeatedly runs a block of code as long as a condition stays true. It's a pre-test loop — the condition is checked before each iteration, so if the condition is false from the start, the body never runs even once.

WHILE is the right choice when you want the loop to run zero or more times and termination naturally fits a top-of-loop check, like "while there are still rows to process" or "while the counter is less than the limit."

[label:] WHILE condition DO statements; END WHILE [label];
ElementPurpose
label:Optional name. Required if you want to use LEAVE or ITERATE from inside the loop, or if it's nested inside another labeled loop.
conditionBoolean expression. The body runs while this stays true.
DO ... END WHILEBrackets around the loop body. Don't forget the trailing semicolon after END WHILE.
  1. Check the condition.
  2. If false → exit the loop, jump to whatever comes after END WHILE.
  3. If true → run the body once.
  4. Go back to step 1.

The crucial part is step 2: because the test runs first, if it's already false on entry, the body is skipped entirely. That's the difference from REPEAT, which always runs the body at least once.

Example 1 — Simple Counter

Print numbers 0 through 9 — the canonical "for i in range(10)" equivalent:

MySQL — WHILE counter
DROP PROCEDURE IF EXISTS while_loop_demo;

DELIMITER $$

CREATE PROCEDURE while_loop_demo()
BEGIN
    DECLARE i        INT DEFAULT 0;
    DECLARE maxCount INT DEFAULT 10;

    WHILE i < maxCount DO
        SELECT i;
        SET i = i + 1;
    END WHILE;
END$$

DELIMITER ;

CALL while_loop_demo();
OUTPUT
mysql — while_loop_demo
mysql>CALL while_loop_demo();
+---+
| i |
+---+
| 0 |
+---+
+---+
| i |
+---+
| 1 |
+---+
| ... (i = 2, 3, 4, 5, 6, 7, 8) |
+---+
| i |
+---+
| 9 |
+---+
10 rows total returned

Notice the loop ran 10 times (i = 0 through i = 9) and stopped exactly when i hit 10 — the condition i < 10 became false at the top of what would have been the 11th iteration.

Example 2 — Accumulating a String

A more practical pattern — build up a comma-separated list of numbers using WHILE, returning a single string:

MySQL — Build a string with WHILE
DROP PROCEDURE IF EXISTS build_csv;

DELIMITER $$

CREATE PROCEDURE build_csv(IN  upto INT,
                           OUT csv  VARCHAR(200))
BEGIN
    DECLARE i INT DEFAULT 1;
    SET csv = '';

    WHILE i <= upto DO
        IF csv = '' THEN
            SET csv = CAST(i AS CHAR);
        ELSE
            SET csv = CONCAT(csv, ',', i);
        END IF;
        SET i = i + 1;
    END WHILE;
END$$

DELIMITER ;

CALL build_csv(7, @list);
SELECT @list;
OUTPUT
mysql — build_csv
mysql>CALL build_csv(7, @list);
Query OK, 0 rows affected (0.00 sec)
mysql>SELECT @list;
+---------------+
| @list |
+---------------+
| 1,2,3,4,5,6,7 |
+---------------+
1 row in set (0.00 sec)
Example 3 — Zero-Iteration Case

To demonstrate the pre-test behavior, call the same procedure with upto = 0:

MySQL — Body never executes
CALL build_csv(0, @list);
SELECT @list;
OUTPUT
mysql — zero iterations
mysql>CALL build_csv(0, @list);
Query OK, 0 rows affected (0.00 sec)
mysql>SELECT @list;
+-------+
| @list |
+-------+
| |
+-------+
1 row in set (0.00 sec)

Empty string. Because i = 1 and upto = 0, the condition i <= upto was false on entry — the loop body never ran. This is the defining behavior of WHILE.

Loop typeTest runsBody runs at least once?Best for
WHILE cond DO ... END WHILETop — before each iterationNo — may run zero timesCounter loops, "while there's still work to do"
REPEAT ... UNTIL cond END REPEATBottom — after each iterationYes — always at least once"Do it once, then keep going until done"
LOOP ... END LOOPWherever you write IF ... LEAVEYes (until LEAVE)Cursor iteration; complex termination logic

Sometimes you want to break out of a WHILE early — not because the main condition became false, but because some other event happened. LEAVE works on any labeled loop, WHILE included:

MySQL — WHILE with early exit
DROP PROCEDURE IF EXISTS find_first_high;

DELIMITER $$

CREATE PROCEDURE find_first_high()
BEGIN
    DECLARE i      INT DEFAULT 1;
    DECLARE found  INT;

    my_while: WHILE i <= 100 DO
        IF i * i > 5000 THEN
            SET found = i;
            LEAVE my_while;        -- exit early
        END IF;
        SET i = i + 1;
    END WHILE my_while;

    SELECT found AS first_n_with_square_over_5000;
END$$

DELIMITER ;

CALL find_first_high();
OUTPUT
mysql — find_first_high
mysql>CALL find_first_high();
+--------------------------------+
| first_n_with_square_over_5000 |
+--------------------------------+
| 71 |
+--------------------------------+
1 row in set (0.00 sec)

712 = 5041, the first square > 5000. The WHILE bailed at i = 71 instead of running all the way to 100.

  1. Make sure something inside the loop changes the condition. The most common WHILE bug is forgetting to increment the counter or update the condition variable — instant infinite loop.
  2. Default to WHILE for counter and "drain a queue" patterns. Use REPEAT only when you genuinely need at-least-once execution; use LOOP only when termination doesn't fit a top-of-loop test.
  3. Label the loop if you need LEAVE or ITERATE, or any time you have nested loops.
  4. Don't use WHILE to do something a single set-based SQL statement could do. A loop that runs UPDATE ... WHERE id = i for each row is much slower than a single UPDATE ... WHERE id IN (...).
  5. Watch for infinite loops on bad input. Add a safety counter (e.g. IF iterations > 10000 THEN LEAVE my_while; END IF;) when the termination depends on data you can't fully trust.
  • WHILE condition DO ... END WHILE is a pre-test loop — the condition is checked before each iteration, so the body may run zero times.
  • Best for counter loops and "while there's still work to do" patterns.
  • If the condition is false on entry, the body never executes — the canonical zero-iteration case.
  • Always make sure something inside the body eventually makes the condition false; otherwise it's an infinite loop.
  • Use LEAVE label for early exit; pair with ITERATE label for "continue" semantics.