Skip to content

MySQL, unlike some programming languages, does not have a direct foreach construct. However, you can implement looping logic using stored procedures and cursors to iterate over rows in a table. This guide explains how to replicate foreach functionality in MySQL, a technique valuable for batch operations or complex data manipulation tasks.

Understanding Cursors for Looping

Cursors in MySQL allow you to iterate through a set of rows returned by a query. They are ideal for situations where you need to process each row individually.

Declaring a Cursor

First, you need to declare a cursor within a stored procedure. This is done after the BEGIN statement.

DECLARE cursor_name CURSOR FOR
SELECT column_name FROM table_name;

Opening and Closing the Cursor

Before using a cursor, you need to open it. Once the operations are complete, the cursor should be closed.

OPEN cursor_name;

-- Perform operations

CLOSE cursor_name;

Processing Rows with Loops

To process each row fetched by the cursor, use a loop within the stored procedure.

Using a CONTINUE HANDLER

A CONTINUE HANDLER is necessary to handle the condition when the cursor runs out of rows.

DECLARE done INT DEFAULT FALSE;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

Looping through the Cursor

Use a REPEAT or WHILE loop to iterate through the rows.

REPEAT
  -- Fetch row from the cursor
  -- Perform operation on each row
UNTIL done END REPEAT;

Example: Updating Rows in a Loop

Here’s an example of using a cursor in a stored procedure to update rows in a table.

CREATE PROCEDURE UpdateRows()
BEGIN
  DECLARE done INT DEFAULT FALSE;
  DECLARE aVariable INT;
  DECLARE cursor_name CURSOR FOR SELECT id FROM table_name;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  OPEN cursor_name;

  read_loop: LOOP
    FETCH cursor_name INTO aVariable;
    IF done THEN
      LEAVE read_loop;
    END IF;

    -- Update statement or other operations
    UPDATE table_name SET column_name = new_value WHERE id = aVariable;
  END LOOP;

  CLOSE cursor_name;
END;

Advanced Use Cases

For more complex scenarios, consider using JOINs or temporary tables to reduce the need for cursors, as they can be resource-intensive.

Using JOINs

When applicable, use JOINs to update or select data from multiple related tables in a single query.

Temporary Tables

In cases where data needs complex processing, inserting data into a temporary table and then processing it can be more efficient.

When to Avoid Cursors

Cursors can be slow and resource-intensive for large datasets. Where possible, use set-based operations with standard SQL queries, as they are generally more efficient.


While MySQL does not have a direct foreach construct, cursors and stored procedures offer a way to iterate over rows in a table. This approach is useful for tasks that require row-by-row processing but should be used judiciously due to potential performance implications. For simpler or set-based operations, standard SQL queries are preferable.

Written by

Robert Cooper avatar

Robert Cooper

Senior Engineer at Basedash

Robert Cooper is a senior engineer at Basedash who builds full-stack product systems across SQL data infrastructure, APIs, and frontend architecture. His work focuses on application performance, developer velocity, and reliable self-hosted workflows that make data operations easier for teams at scale.

View full author profile →

Looking for an AI-native BI tool?

Basedash lets you build charts, dashboards, and reports in seconds using all your data.