文章目录
- 简介
- 什么是游标
- 如何使用游标
- 参考文献
简介
sql编程与传统编程最大的区别之一,就是sql是面向集合的思考方式,更加关注“获取什么”,而不是如何获取。因为sql本身是以关系模型和集合论作为基础的。
在有的情况下,我们不需要对查询结果集中的所有数据行都采用相同的处理,而只是每次处理一行或者一部分行,这时候就需要面向过程编程。
游标就是这种编程方式的体现,或者说是SQL为了实现面向过程而做的一个扩充(其实应用面不大)。如果你有面向过程编程的经验的话,对于游标的理解会更容易一些。
我们需要关注的几个问题:
- 什么是游标?我们为什么要使用游标?
- 如何使用游标?
- 日常中使用游标的案例。
看完下面对游标的介绍,其实大概能得出结论,游标一般适用的是那种需要对不同类型数据行做不同处理的场景,或者是某行的更新需要按照前面的行来进行的场景,相对应用面比较窄。
而且游标对性能的影响也比较大,比如说在使用的过程中,会对数据行进行加锁(有时关闭游标时才会释放),比较会影响效率,另外它的操作都是在内存中进行的,因此对资源的消耗也比较大。
再就是写起来也费劲。
所以现实的生产环境里一般也不会用游标,可以考虑使用case when或者Python等编程语言来替代。因此本节只是从教程里摘取了部分知识点,做简单的介绍,对原理并没有深入。
什么是游标
教程的评论里,有个老哥写的很好,深以为然,他说他更倾向于使用case的方式来处理例子里的业务,但是游标也有自己不可被替代的场景,即,如果某行的更新需要根据前面的行数据来做时,游标就会更加适用。
使用游标会降低查询性能,如无必要,不要使用游标。
在SQL里,游标是一种临时的数据库对象,它其实是数据表中的数据行指针,没错,就是我们在编程时通常理解的那个指针。
如何使用游标
大概有五步。在不同DBMS里,使用游标的语法会有不同,这里主要以MySQL举例来讲。
第一步,定义游标。
MySQL、SQL Server、DB2和MarinaDB里是这么写:
DECLARE cursor_name CURSOR FOR select_statement
而Oracle和PostgreSQL,是写成:
DECLARE cursor_name CURSOR IS select_statement
这里的select_statement就是指需要执行的select语句,但是这里还没开始遍历数据。
比如说,我想定义一个能存储heros表中最大生命值的游标,可以写成:
DECLARE cur_hero CURSOR FOR SELECT hp_max FROM heros;
第二步,打开游标:
OPEN cursor_name
打开游标的时候,select语句就会被执行,并把查询结果集发送到游标工作区(在内存)。
第三步,从游标中取得数据:
FETCH cursor_name INTO var_name ...
这句的意思是,使用cursor_name这个游标读取当前行,并将数据保存到var_name这个变量里,最后,游标自动++,指到下一行。
如果游标读取的数据行有多个列,那么在into后面多写几个变量名,逗号隔开就行。
这句话一般是放在循环里循环执行的。
第四步,关闭游标:
CLOSE cursor_name
游标关闭后就不能使用了。再使用的话,只能重新打开。
第五步,释放游标:
DEALLOCATE cursor_namec
主动释放内存资源。
接下来,抄一下教程里给出的游标应用示例,即用游标来扫描heros数据表中的数据行,并累计生命值字段,输出。
CREATE PROCEDURE `calc_hp_max`()
BEGIN-- 创建接收游标的变量DECLARE hp INT; -- 创建总数变量 DECLARE hp_sum INT DEFAULT 0;-- 创建结束标志变量 DECLARE done INT DEFAULT false;-- 定义游标 DECLARE cur_hero CURSOR FOR SELECT hp_max FROM heros;-- 指定游标循环结束时的返回值 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true; OPEN cur_hero;read_loop:LOOP FETCH cur_hero INTO hp;-- 判断游标的循环是否结束,否则游标到最后一行时再++会报错IF done THEN LEAVE read_loop;END IF; SET hp_sum = hp_sum + hp;END LOOP;CLOSE cur_hero;SELECT hp_sum;
END
当然,上面的案例只是用来介绍下游标具体是怎么用的,如果真的想完成求累加和的目的的话,直接sum就可以了。
参考文献
- 16丨游标:当我们需要逐条处理数据时,该怎么做?
- MySQL ------ 游标(CURSOR)(二十六)