![]() |
VOOZH | about |
A MySQL cursor is a powerful database object designed for retrieving, processing, and managing rows from a result set one at a time. Unlike standard SQL queries that handle sets of rows in bulk, cursors allow for detailed row-by-row operations. In this article, We will learn about MySQL Cursors in detail.
A cursor is declared within a stored procedure or function using a CURSOR statement. This binds the cursor to a specified SQL query.
DECLARE cursor_name CURSOR FOR select_statement;You need to open the cursor before you fetch rows from it. You do this with the OPEN statement.
OPEN cursor_name;The FETCH statement retrieves the data from the cursor and moves the cursor to the next line in the result set; it loads the data into variables.
FETCH cursor_name INTO variable1, variable2, ...;Finally, you would close the cursor after you have processed all the data, so that the resources that are allocated for it will be released.
CLOSE cursor_name;DELIMITER //
CREATE PROCEDURE ProcessOrders()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE order_id INT;
DECLARE order_amount DECIMAL(10, 2);
-- Declare the cursor
DECLARE order_cursor CURSOR FOR
SELECT id, amount FROM orders WHERE status = 'pending';
-- Declare a handler for the NOT FOUND condition
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- Open the cursor
OPEN order_cursor;
-- Loop through the rows
read_loop: LOOP
FETCH order_cursor INTO order_id, order_amount;
IF done THEN
LEAVE read_loop;
END IF;
-- Process each row
UPDATE orders SET status = 'processed' WHERE id = order_id;
END LOOP;
-- Close the cursor
CLOSE order_cursor;
END //
DELIMITER ;
Explanation:
The example below shows using a cursor to process all rows subject to conditions, in order to update them.
DELIMITER //
CREATE PROCEDURE UpdateOrderStatus()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE order_id INT;
DECLARE order_amount DECIMAL(10, 2);
-- Declare the cursor
DECLARE order_cursor CURSOR FOR
SELECT id, amount FROM orders WHERE status = 'pending';
-- Declare a handler for the NOT FOUND condition
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- Open the cursor
OPEN order_cursor;
-- Loop through the rows
read_loop: LOOP
FETCH order_cursor INTO order_id, order_amount;
IF done THEN
LEAVE read_loop;
END IF;
-- Example logic: If order amount is greater than 1000, update status
IF order_amount > 1000 THEN
UPDATE orders SET status = 'high_value' WHERE id = order_id;
ELSE
UPDATE orders SET status = 'processed' WHERE id = order_id;
END IF;
END LOOP;
-- Close the cursor
CLOSE order_cursor;
END //
DELIMITER ;
Explanation:
This example shows how to use a cursor with error handling in place, so that any exceptions thrown off of the operations on the cursor are caught.
DELIMITER //
CREATE PROCEDURE ProcessSales()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE sale_id INT;
DECLARE sale_total DECIMAL(10, 2);
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
-- Handle SQL exceptions
ROLLBACK;
SELECT 'An error occurred. Transaction rolled back.';
END;
-- Declare the cursor
DECLARE sales_cursor CURSOR FOR
SELECT id, total FROM sales WHERE processed = FALSE;
-- Declare a handler for the NOT FOUND condition
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- Start a transaction
START TRANSACTION;
-- Open the cursor
OPEN sales_cursor;
-- Loop through the rows
read_loop: LOOP
FETCH sales_cursor INTO sale_id, sale_total;
IF done THEN
LEAVE read_loop;
END IF;
-- Example logic: Process each sale and handle errors
BEGIN
-- Some processing logic (e.g., update sale status)
UPDATE sales SET processed = TRUE WHERE id = sale_id;
END;
END LOOP;
-- Close the cursor
CLOSE sales_cursor;
-- Commit the transaction
COMMIT;
END //
DELIMITER ;
Explanation:
Overall, MySQL cursors provide a way to handle and process data one row at a time, which is useful for complex tasks that require detailed operations. They allow precise control over data manipulation within stored procedures. However, while powerful, cursors can impact performance compared to set-based operations, so they should be used carefully to balance detail with efficiency.