在数据库中,游标是一个十分重要的概念。游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。游标总是与一条SQL 选择语句相关联因为游标由结果集(可以是零条、一条或由相关的选择语句检索出的多条记录)和结果集中指向特定记录的游标位置组成。当决定对结果集进行处理时,必须声明一个指向该结果集的游标。如果曾经用 C 语言写过对文件进行处理的程序,那么游标就像您打开文件所得到的文件句柄一样,只要文件打开成功,该文件句柄就可代表该文件。对于游标而言,其道理是相同的。可见游标能够实现按与传统程序读取平面文件类似的方式处理来自基础表的结果集,从而把表中数据以平面文件的形式呈现给程序。
游标允许应用程序对查询语句select 返回的行结果集中每一行进行相同或不同的操作,而不是一次对整个结果集进行同一种操作;它还提供对基于游标位置而对表中数据进行删除或更新的能力;而且,正是游标把作为面向集合的数据库管理系统和面向行的程序设计两者联系起来,使两个数据处理方式能够进行沟通。
一,什么是游标(cursor)
个人觉得就是一个cursor,就是一个标识,用来标识数据取到什么地方了。你也可以把它理解成数组中的下标。
二,游标(cursor)的特性
1,只读的,不能更新的。
2,不滚动的
3,不敏感的
游标(cursor)必须在声明处理程序之前被声明,并且变量和条件必须在声明游标或处理程序之前被声明。
三、游标的优点
1、游标是针对行操作的,对从数据库中 select 查询得到的结果集的 每一行可以进行分开的独立的相同或者不相同的操作,是一种分离的思想。
四、游标的缺点
1.性能不高
2.只能一行一行操作
3.使用游标会产生死锁,造成内存开销大
五、游标的适用场景
1.存储过程
2.函数
3.触发器
4.事件
cursor游标
• Cursor游标用来声明一个数据集
• 游标的声明必须在变量和条件声明之后,在handler声明之前
• Cursor close语句用来关闭之前打开的游标
cursor游标
• Cursor游标用来声明一个数据集
• 游标的声明必须在变量和条件声明之后,在handler声明之前
cursor游标close语句
• Cursor close语句用来关闭之前打开的游标
• 如果关闭一个未打开的游标,则MySQL会报错
• 如果在存储过程和函数中未使用此语句关闭已经打开的游标,则游标会在声明的begin…end语句块执行完之后自动关闭
cursor游标declare语句
• Cursor declare语句用来声明一个游标和指定游标对应的数据集合,通常数据集合是一个select语句
• Select_statement代表一个select语句
cursor游标fetch语句
• Cursor fetch语句用来获取游标指定数据集的下一行数据并将各个字段值赋予后面的变量
• 数据集中的字段需要和INTO语句中定义的变量一一对应
• 数据集中的数据都fetch完之后,则返回NOT FOUND
cursor游标open语句
• Open cursor语句用来打开一个之前已经声明好的游标
Declare condition语句
• Declare condition语句命名特定的错误条件,而该特定错误可以在declare…handler中指定处理方法
• Condition_value指定特定的错误条件,可以有以下两种形式
• Mysql_err_code表示MySQL error code的整数
• SQLSTATE sqlstate_value表示MySQL中用5位字符串表达的语句状态
• 比如在MySQL中1051error code表示的是unknown table的错误,如果要对这个错误做特殊处理,可以用三种种方法:
• DECLARE CONTINUE HANDLER FOR 1051
• BEGIN
• -- body of handler
• END;
• DECLARE no_such_table CONDITION FOR 1051;
• DECLARE CONTINUE HANDLER FOR no_such_table
• BEGIN
• -- body of handler
• END;
• DECLARE no_such_table CONDITION FOR SQLSTATE '42S02';
• DECLARE CONTINUE HANDLER FOR no_such_table
• BEGIN
• -- body of handler
• END;
Declare handler语句
• Declare handler语句用来声明一个handler来处理一个或多个特殊条件,当其中的某个条件满足时则触发其中的statement语句执行
• Statement可以是一个简单SQL语句,也可以是begin…end组成的多个语句
DROP PROCEDURE IF EXISTS teacher_select; delimiter // CREATE PROCEDURE teacher_select () BEGIN DECLARE done INT DEFAULT FALSE ; DECLARE v_tno VARCHAR (15) ; DECLARE v_tname VARCHAR (20) ; DECLARE cur1 CURSOR FOR SELECT tno, tname FROM teacher ; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE ; #当fetch不到数据时,会执行这个,这是一个错误判断,当达到某个条件的时候,就会执行 OPEN cur1 ; FETCH cur1 INTO v_tno, v_tname ; WHILE ! done DO -----#程序逻辑 FETCH cur1 INTO v_tno, v_tname ; END WHILE ;
close cur1; END// delimiter ;
比如:
mysql> select tno,tname from teacher; +------+-----------+ | tno | tname | +------+-----------+ | t001 | 刘阳 | | t002 | 谌燕 | | t003 | 胡明星 | +------+-----------+ 3 rows in set (0.00 sec)
DROP PROCEDURE IF EXISTS teacher_select; delimiter // CREATE PROCEDURE teacher_select () BEGIN DECLARE done INT DEFAULT FALSE ; DECLARE v_tno VARCHAR (15) ; DECLARE v_tname VARCHAR (20) ; DECLARE cur1 CURSOR FOR SELECT tno, tname FROM teacher ; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE ; # OPEN cur1 ; FETCH cur1 INTO v_tno, v_tname ; WHILE ! done DO SELECT v_tno, v_tname ; FETCH cur1 INTO v_tno, v_tname ; END WHILE ; CLOSE cur1 ; END// delimiter ;
mysql> CALL teacher_select (); +-------+---------+ | v_tno | v_tname | +-------+---------+ | t001 | 刘阳 | +-------+---------+ 1 row in set (0.00 sec) +-------+---------+ | v_tno | v_tname | +-------+---------+ | t002 | 谌燕 | +-------+---------+ 1 row in set (0.00 sec) +-------+-----------+ | v_tno | v_tname | +-------+-----------+ | t003 | 胡明星 | +-------+-----------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql>
• Handler_action子句声明当执行完statement语句之后应该怎么办
• Continue代表继续执行该存储过程或函数
• Exit代表退出声明此handler的begin…end语句块
• Undo参数已经不支持
• Condition_value的值有以下几种:
• Mysql_err_code表示MySQL error code的整数
• SQLSTATE sqlstate_value表示MySQL中用5位字符串表达的语句状态
• Condition_name表示之前在declare…condition语句中声明的名字
• SQLWARNING表示所有的警告信息,即SQLSTATE中01打头的所有错误
• NOT FOUND表示查完或者查不到数据,即SQLSTATE中02打头的所有错误
• SQLEXCEPTION表示所有的错误信息
• DECLARE CONTINUE HANDLER FOR 1051
• BEGIN
• -- body of handler
• END;
•
• DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
• BEGIN
• -- body of handler
• END;
•
• DECLARE CONTINUE HANDLER FOR SQLWARNING
• BEGIN
• -- body of handler
• END;
•
• DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
• BEGIN
• -- body of handler
• END;
• 当condition发生但没有声明handler时,则存储过程和函数依照如
下规则处理
• 发生SQLEXCEPTION错误,则执行exit退出
• 发生SQLWARNING警告,则执行contine继续执行
• 发生NOT FOUND情况,则执行continue继续执行
DROP PROCEDURE IF EXISTS teacher_insert; delimiter // CREATE PROCEDURE teacher_insert () BEGIN INSERT INTO teacher (tno, tname) ; VALUES ('t004', '胡桃里1') ; INSERT INTO teacher (tno, tname) VALUES ('t001', '胡桃里2') ; INSERT INTO teacher (tno, tname) VALUES ('t005', '胡桃里3') ; END// delimiter ;
执行结果:
符合当condition发生但没有声明handler时,发生SQLEXCEPTION错误,则执行exit退出
mysql> SELECT * FROM teacher ; +------+-----------+ | tno | tname | +------+-----------+ | t001 | 刘阳 | | t002 | 谌燕 | | t003 | 胡明星 | +------+-----------+ 3 rows in set (0.01 sec) mysql> CALL teacher_insert (); ERROR 1062 (23000): Duplicate entry 't001' for key 'PRIMARY' mysql> SELECT * FROM teacher ; +------+------------+ | tno | tname | +------+------------+ | t001 | 刘阳 | | t002 | 谌燕 | | t003 | 胡明星 | | t004 | 胡桃里1 | +------+------------+ 4 rows in set (0.00 sec) mysql>
声明handler,让遇到SQLEXCEPTION 错误23000时,继续执行往下执行
DROP PROCEDURE IF EXISTS teacher_insert2; delimiter // CREATE PROCEDURE teacher_insert2 () BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @done = TRUE ; INSERT INTO teacher (tno, tname) VALUES ('t004', '胡桃里1') ; INSERT INTO teacher (tno, tname) VALUES ('t001', '胡桃里2') ; INSERT INTO teacher (tno, tname) VALUES ('t005', '胡桃里3') ; END// delimiter ;
执行结果:
mysql> SELECT * FROM teacher ; +------+-----------+ | tno | tname | +------+-----------+ | t001 | 刘阳 | | t002 | 谌燕 | | t003 | 胡明星 | +------+-----------+ 3 rows in set (0.00 sec) mysql> CALL teacher_insert2 (); Query OK, 1 row affected (0.08 sec) mysql> SELECT * FROM teacher ; +------+------------+ | tno | tname | +------+------------+ | t001 | 刘阳 | | t002 | 谌燕 | | t003 | 胡明星 | | t004 | 胡桃里1 | | t005 | 胡桃里3 | +------+------------+ 5 rows in set (0.01 sec) mysql>