游标
游标的基本概念
什么是游标?
在查询表时,会获得一个查询结果集,游标就是用来遍历这个结果集中每一条记录的,把查询结果集看作是一个容器,那游标就是类似于迭代器一样的东西,游标可以返回结果集中一行或多行数据,结果集是存在数据缓冲区里的,游标可以从数据缓冲区里读取相应的数据。
游标只能用在存储过程和函数中,并且一次只能指向一条记录。
游标类似于C语言中的指针,可以指向一块数据内存,然后通过这块数据进行访问,也可以理解成c++中的容器的迭代器
游标的使用
1.声明游标(定义游标)
declare 游标名 cursor for select 查询语句;
2.打开定义的游标
open 游标名;
3.遍历游标(使用游标)
fetch 游标名 into 值列表(变量);
4.使用完释放游标(关闭游标)
close 游标名;
注意:
游标在遍历完成后会指向最后一条记录的下一条,由于下一条没有数据,就会出现 no data to fetch 的错误。
为了解决这个错误,就需要定义一个条件处理函数NOT FOUND 来捕获这一个异常。没有异常处理的话就会报错。
declare 游标 cursor for # 定义游标
select 属性名 from 表格 where 条件;
声明错误处理函数 not found ,来捕获遍历结束的错误
declare continue handler for not found;
示例,读取一张成绩表中的内容
delimiter $$
create procedure cursor_test()
begin
##定义三个变量
declare id int;
declare title varchar(255);
declare c_date date;
##统计的变量
declare counts int default 0;
##退出的条件
declare cur_exit bool default false;
##定义游标
declare cur_test cursor for select * from course_tb;
## 条件处理,遇到没有找到数据的错误,就执行一段命令
##当游标读到末尾的时候,就将退出的条件设置为true
## 这条命令要写在定义游标之后
declare continue handler for not found set cur_exit=true;
## 打开游标
open cur_test;
##循环遍历
cur:loop
## 遍历游标
fetch cur_test into id,title,c_date;
## 如果退出的条件为true,就跳出
if cur_exit then leave cur;
##跳出循环
end if;
select id,title,c_date;
set counts=counts+1;
end loop;
select counts;
##关闭游标
close cur_test;
end$$
delimiter ;
条件处理
条件处理就是MySQL数据库中的异常处理(错误处理)。
MySQL通过条件处理来捕获错误和异常。
注意:条件处理只能在存储过程中使用,并且存储过程和条件处理只有 MySQL5.5 版本之后才支持,如 果用的是 MySQL5.5 之前的版本就不要用条件处理了。
定义处理函数
使用命令行中的语句获取语法格式(? declare handler)
DECLARE handler_action HANDLER ##handler_action 捕获选项
FOR 错误值 [, condition_value]
...statement #怎么处理
handler_action选项
捕获后怎么处理? 继续 | 退出 | 不处理(MySQL不支持)
handler_action: continue | exit | UNDO # 处理动作名
continue 继续,遇到错误继续执行代码
exit 退出,遇到错误直接结束命令
condition_value: # 错误值
mysql_error_code | SQLSTATE [VALUE] sqlstate_value
错误码 | 状态值
| condition_name | SQLWARNING | NOT FOUND | SQLEXCEPTION
条件处理实例
无错误处理的存储过程
#无错误处理的存储过程
create procedure p_test1()
begin
select * from untable;
end;
call p_test1();
出现错误
ERROR 1146 (42S02): Table 'tzdb5.untable' doesn't exist
调用存储过程后会报错:错误码 1146 (42S02)表不存在
所有 mysql 中所定义的错误码和状态值都可以在存储过程中用错误码进行错误处理
create procedure p_test2()
begin
declare continue handler for 1146
select '此表不存在' as 错误;
#使用一个不存在的表
select * from untable; ## 出现了错误
end;
call p_test2();
调用存储过程后不会报错,而是按照自己所设置的进行处理
在存储过程中用状态值进行错误处理
create procedure p_test3()
begin
declare continue handler for sqlstate '42S02'
select '此表真的不存在' as 错误;
#使用一个不存在的表
select * from untable;
end;
call p_test3();
错误条件函数
错误条件函数的声明(? declare condition)
可以进行手动的设置错误码,和错误信息
DECLARE condition_name(错误函数名) #错误条件函数
CONDITION FOR condition_value(状态值) #声明一个条件处理
错误条件函数相当于给错误取别名,通过别名来显示错误信息
condition_value: # 条件值
mysql_error_code # 错误码
| SQLSTATE [VALUE] sqlstate_value
状态类 错误类名
例如:
use 一个不存在的数据库名;
# 使用不存在的数据库 use untable;
出现下面错误
ERROR 1049 (42000): Unknown database 'untable'
1049为错误码,42000为状态类
声明错误条件不能单独使用,要配合处理函数使用
1.在存储过程中用错误码进行错误处理
create procedure test4_pro()
begin
declare no_table condition for 1146;
select * from untable;
end$$
call test4_pro();
2.在存储过程中用状态值进行错误处理
create procedure p_test5()
begin
##声明错误函数
declare no_have_table condition for sqlstate '42S02';
#通过条件处理调用错误函数
declare continue handler for no_have_table
select '说了此表不存在了还查' as 错误;
select * from untable;
end;
call p_test5();
获取错误信息
通过 get diagnostics 获取错误信息。
一般格式
get diagnostics condition 错误信息位置
@变量名1= mysql_errno, # 获取错误码
@变量名2= returned_sqlstate, # 获取状态值
@变量名3= message_text; # 获取错误信息文本
修改错误信息日志
#如:删除一个不存在的表,
drop table untable;
#ERROR 1051 (42S02): Unknown table 'tzdb.untable'
get diagnostics condition 1
@x = mysql_errno,
@y = returned_sqlstate,
@z = message_text;
更改错误信息
错误信息 | 描述 |
---|---|
schema_name | 数据库名 |
table_name | 表名 |
message_text | 错误信息 |
mysql_errno | 错误码 |
returned_sqlstate | 错误状态值 |
通过 resignal / signal 更改错误信息。
一般格式:创建一个存储过程实现错误信息的
## 声明错误信息处理的函数
declare no_table condition for 1146;
signal需要指定错误信息
##手动设置一个错误信息
begin declare continue handler for sqlstate '42S02'
begin signal sqlstate '42S02' # sqlstate '42S02' = 1051
#这里使用resignal不用指定错误,直接写个resignal就可以了
set schema_name = 'newdb', #数据库名
table_name = 'newdb_tb', #表名
message_text = '没有这个表', #错误信息
mysql_errno = 11; #错误码
end;
drop table untable;
end; #调用存储过程
call test_signal();
#resignal默认修改上一条错误信息
RESIGNAL语句。它在功能和语法方面与SIGNAL语句相似
区别:
必须在错误或警告处理程序中使用RESIGNAL语句,可以在存储过程中的任何位置使用SIGNAL语句。
可以省略SIGNAL语句的所有属性,默认修改上一条错误信息
其他错误信息
错误信息 | 描述 |
---|---|
subclass_origin | 原始子类名 |
constraint_catalog | 约束目录 |
constraint_name | 约束名 |
catalog_name | 目录名 |
column_name | 列名 |
cursor_name | 游标 |