Documentation Home
MySQL 5.5 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 27.2Mb
PDF (A4) - 27.2Mb
PDF (RPM) - 25.8Mb
HTML Download (TGZ) - 6.5Mb
HTML Download (Zip) - 6.6Mb
HTML Download (RPM) - 5.6Mb
Man Pages (TGZ) - 158.5Kb
Man Pages (Zip) - 262.1Kb
Info (Gzip) - 2.6Mb
Info (Zip) - 2.6Mb
Excerpts from this Manual

13.6.6 Cursors

MySQL supports cursors inside stored programs. The syntax is as in embedded SQL. Cursors have these properties:

  • Asensitive: The server may or may not make a copy of its result table

  • Read only: Not updatable

  • Nonscrollable: Can be traversed only in one direction and cannot skip rows

Cursor declarations must appear before handler declarations and after variable and condition declarations.

Example:

CREATE PROCEDURE curdemo()
BEGIN
  DECLARE done INT DEFAULT FALSE;
  DECLARE a CHAR(16);
  DECLARE b, c INT;
  DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
  DECLARE cur2 CURSOR FOR SELECT i FROM test.t2;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  OPEN cur1;
  OPEN cur2;

  read_loop: LOOP
    FETCH cur1 INTO a, b;
    FETCH cur2 INTO c;
    IF done THEN
      LEAVE read_loop;
    END IF;
    IF b < c THEN
      INSERT INTO test.t3 VALUES (a,b);
    ELSE
      INSERT INTO test.t3 VALUES (a,c);
    END IF;
  END LOOP;

  CLOSE cur1;
  CLOSE cur2;
END;

User Comments
User comments in this section are, as the name implies, provided by MySQL users. The MySQL documentation team is not responsible for, nor do they endorse, any of the information provided here.
  Posted by David Bergan on February 23, 2012
In response to Alexander Pelov's situation...

The problem is that when one of your SELECT INTO queries within the loop generates 0 results... it trips the CONTINUE HANDLER and sets "done = TRUE". The easiest way around this is to simply add the line "SET done = FALSE ;" immediately before the FETCH command(s) like so...

read_loop: LOOP
-- This is the line that fixes the problem
SET done = FALSE ;

FETCH cur1 INTO a, b;
FETCH cur2 INTO c;

IF done THEN
LEAVE read_loop;
END IF;
IF b < c THEN
INSERT INTO test.t3 VALUES (a,b);
ELSE
INSERT INTO test.t3 VALUES (a,c);
END IF;

-- This is the kind of line that would cause the problem.
-- SELECT INTO returns 0 records, triggering the CONTINUE HANDLER and setting done to TRUE (which we don't want)
SELECT id INTO a FROM test.t1 WHERE 1 = 2 ;
END LOOP;


This way, "done" is reset to false from whatever else went on during the loop and the "IF done THEN" check could only be true when FETCH runs out of records.
  Posted by Brent Roady on May 9, 2012
It should be noted that the local variable names used in FETCH [cursor] INTO must be different than the variable names used in the SELECT statement defining the CURSOR. Otherwise the values will be NULL.

In this example,

DECLARE a VARCHAR(255);
DECLARE cur1 CURSOR FOR
SELECT a FROM table1;
FETCH cur1 INTO a;

the value of a after the FETCH will be NULL.

This is also described here: http://bugs.mysql.com/bug.php?id=28227
  Posted by Jérémi Lassausaie on February 3, 2015
Answer for Brent Roady :

I don't see any bug in the bahaviour described.

DECLARE a VARCHAR(255);
/* you declare a variable "a" without a specified default value, a=NULL */

DECLARE cur1 CURSOR FOR
SELECT a FROM table1;
/* You declare a cursor that selects "a" FROM a table */

OPEN cur1;
/* You execute your cursor query, a warning is raised because a is ambiguously defined but you don't see it */

FETCH cur1 INTO a;
/* you put your unique field in your unique row into a (basically you do "SET a=a;") so a is still NULL */

There is no bug report, just a misunderstanding.
Sign Up Login You must be logged in to post a comment.