
MySQL позволяет использовать курсоры (CURSORs) в хранимых процедурах. Эта конструкция позволяет организовать сложную обработку данных на стороне сервера привычным программисту способом, а именно — строка за строкой. Обработка данных на стороне MySQL может сократить время обработки данных, т.к. не нужно передавать данные из базы в программу и наоборот, как это часто происходит при работе с базой из PHP скрипта на веб-сервере.
Дальше мы разберем как объявить и работать с курсорами.
При работе с курсорами надо помнить, что они :
- нечувствительны к изменениям в базе; то есть после выполнения запроса, данные там статичны;
- работают только на чтение (readonly);
- просматривают результаты только в одном направлении и не могут «перескакивать» через строки.
Фазы жизни курсора
Курсоры объявляются в начале хранимой процедуры до выполнения каких либо операций.
| 1 2 3 4 5 | //пара переменных для последующей выборки данных курсора DECLARE a, b INT; //объявляем курсор, выбирающий пары значений из некой тестовой таблицы DECLARE cur1 CURSOR FOR  SELECT value_a, value_b FROM test.t1; | 
Перед выборкой строк из курсора его нужно инициализировать (выполняется запрос)
| 1 | OPEN cur1; | 
Далее вы можете выбирать данные из курсора, строка за строкой.
| 1 2 3 4 5 6 7 8 | //помещаем следующую пару значений в переменные a и b FETCH cur1 INTO a, b; //выполняем какие то манипуляции с данными IF a < b THEN    ... ELSE    ... END IF; | 
Завершается работа с курсором вот так:
| 1 | CLOSE cur1; | 
Признак отсутствия данных в курсоре
В показанном примере выше, мы вообще то не знаем, вернул ли запрос в курсоре хотя бы одну строку. И выполняем операцию FETCH только для одной строки запроса, хотя их может быть больше. Нам нужен сигнал об окончании данных в курсоре. В MySQL для этого используют обработку исключительных ситуаций — конструкцию
| 1 | DECLARE .. HANDLER FOR ... { } | 
В нашем случае нужно продолжить исполнение (CONTINUE) при возникновении ситуации «нет данных» (NOT FOUND).
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | //объявим дополнительно переменную-флажок //этот флаг будет хранить сигнал об окончании данных в курсоре DECLARE done INT DEFAULT FALSE; DECLARE a, b INT; DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1; //описываем как действовать во время исключения DECLARE CONTINUE HANDLER FOR NOT FOUND  //а именно : установим флаг SET done = TRUE; //если нужно выполнить несколько команд - используйте операторные скобки //BEGIN ... END; //инициализация OPEN cur1; //цикл чтения курсора read_loop: LOOP     FETCH cur1 INTO a, b;     //проверка флага     IF done THEN         LEAVE read_loop;     END IF;     //обработка данных     ... END LOOP; //завершаем работу с курсором CLOSE cur1; | 
Думаю, этой информации достаточно, чтобы начать использовать курсоры. Есть вопросы — пишите :)
