SQL Cursor in Stored Procedures
MySQL supported cursor in stored procedures, functions and triggers. Cursor is used to iterate through a set of rows, which returned by a query, and process individual row. Currently with all versions greater 5.x, MySQL cursor has following properties:
- Read only: it means you cannot update the cursor.
- Non-scrollable: it only can traverse in one direction and cannot skip, move back or forth in result set.
- Asensitive: you should avoid update table while open a cursor on that table otherwise you may get unexpected results.
MySQL supports following statements for working with cursor.
First you have to declare a cursor using DECLARE statement:
DECLARE cursor_name CURSOR FOR SELECT_statement;
Second you have to open the cursor using OPEN statement. You must open cursor before fetching rows from it.
OPEN cursor_name;
Next you can retrieve next row from cursor and move the cursor to the following row in a result set by using FETCH statement.
FETCH cursor_name INTO variable list;
And finally, you must close the cursor to deactivate it and release the memory associated with that cursor. To close the cursor you use CLOSE statement:
CLOSE cursor_name;
One of the most important point when working with cursor is you should use a NOT FOUND handler to avoid raising a fatal “no data to fetch” condition.
We use a stored procedure example bellow to demonstrate cursor.
DELIMITER $$
DROP PROCEDURE IF EXISTS CursorProc$$
CREATE PROCEDURE CursorProc()
BEGIN
DECLARE no_more_products, quantity_in_stock INT DEFAULT 0;
DECLARE prd_code VARCHAR(255);
DECLARE cur_product CURSOR FOR
SELECT productCode FROM products;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_products = 1;
/* for loggging information */
CREATE TABLE infologs (
Id int(11) NOT NULL AUTO_INCREMENT,
Msg varchar(255) NOT NULL,
PRIMARY KEY (Id)
);
OPEN cur_product;
FETCH cur_product INTO prd_code;
REPEAT
SELECT quantityInStock INTO quantity_in_stock
FROM products
WHERE productCode = prd_code;
IF quantity_in_stock < 100 THEN
INSERT INTO infologs(msg)
VALUES (prd_code);
END IF;
FETCH cur_product INTO prd_code;
UNTIL no_more_products = 1
END REPEAT;
CLOSE cur_product;
SELECT * FROM infologs;
DROP TABLE infologs;
END$$
DELIMITER;
The stored procedure is very simple and can archive the same result by SQL query. We use it only for demonstrating how cursors work.
We use a cursor for products table and loop though the products result set. If the quantity in stock of a product is less than 100, we log it into to a temporary table and after the loop we select all products to print it on screen.
Remember you must declare cursor first and then declare a NOT FOUND handler; otherwise you will get an error.