MySQL 游标的详解讲解


每博一文案

曾经看过一个这样的故事:
有一个人非常喜爱金币,他从年轻的时候就开始收集、累积金币。
直到有一天他存了三万个金币,他想好好地享受接下来的生活,不想再累积、追求金币了。
正当他这样想时,有一个老人突然来找他,这位老人就是死神。
死神对他说:“你的生命已到尽头了,我是来带你走的。”
这个人非常吃惊,好不容易累积了三万个金币,居然现在就要走了。
于是他要求死神再给他三天时间,并愿意分给死神一万个金币,死神不答应。
他以为死神嫌太少,于是要求只要给他两天的时间,就分给死神两万个金币,死神仍然不答应。
他又要求死神给他一天的时间,就分给死神三万个金币,死神还是不答应。
最后,他哭着要求死神,只要给他三分钟,写几句话给后代的人,他便给死神三万个金币。
死神看他那么可怜,终于答应给他三分钟,他便在纸上写了一句话:
“世人啊!请好好珍惜人生的时光吧!因为三万个金币也买不回一个小时。”如果没了生命,再多的钱也都没有意义。
人生短暂,就像石头相撞时所发出的一点火花转瞬即逝。
智者和愚者的区别就在于谁懂得珍惜健康,愚者用健康换取财富,智者为健康可放下一切。
没有什么事情,值得我们用健康去交换。——————   一禅心灵庙语

文章目录

  • MySQL 游标的详解讲解
    • 每博一文案
    • 1. 游标的概念
    • 2. 使用游标的步骤
    • 3. 游标的使用案例
    • 4. 小结
    • 5. 最后:

1. 游标的概念

虽然我们也可以通过筛选条件 WHEREHAVING ,或者是限定返回记录的关键字 LIMIT 返回一条记录。但是却无法在结果集中像指针一样,向前定位一条记录,向后定位一条记录,或者是随意定位到某一条记录。并对记录的数据进行处理。

这个时候,就可以用到游标。游标,提供了一种灵活的操作方式,让我们能够对结果集中的每一条记录,进行定位,并对指向的记录中的数据进行操作的数据结构。游标让 SQL 这种面向集合的语言有了面向过程开发的能力。

在 SQL 中,游标是一种临时的数据库对象,可以指向存储在数据库表中的数据行指针。这里游标充当了指针的作用,我们可以操作游标对数据进行操作。

我们其实可以把游标理解成是一个查询的结果集,让我们可以通过像操作指针一样定位,到结果集中的某个记录,修改,取出数据

MySQL中游标可以在存储过程和函数中使用。

比如,我们查询了 employees 数据表中工资高于15000的员工都有哪些:

SELECT employee_id,last_name,salary FROM employees
WHERE salary > 15000;

这里我们就可以通过游标来操作数据行,如图所示此时游标所在的行是“108”的记录,我们也可以在结果 集上滚动游标,指向结果集中的任意一行。

2. 使用游标的步骤

游标必须在声明处理程序之前被声明,并且变量和条件还必须在声明游标或处理程序之前被声明。如果我们想要使用游标,一般需要经历 四个步骤 。不同的 DBMS 中,使用游标的语法可能略有不同。

第一步:声明游标

在MySQL中,使用 DECLARE 关键字来声明游标,其语法的基本形式如下:

DECLARE cursor_name CURSOR FOR select..(查询结果集);

这个语法适用于 MySQL,SQL Server,DB2 和 MariaDB。如果是用 Oracle 或者 PostgreSQL,需要写成:

DECLARE cursor_name CURSOR IS select_statement;

要使用 SELECT 语句来获取数据结果集,而此时还没有开始遍历数据,这里 select_statement 代表的是 SELECT 语句,返回一个用于创建游标的结果集。

比如:

DECLARE cursor_emp CURSOR FOR
SELECT employee_id,salary FROM employees;
DECLARE cur_emp CURSOR FOR
SELECT last_name, salary FROM employees;

第二步:打开游标

当我们定义好游标之后,如果 想要使用游标,就必须先打开我们定义好的游标,打开游标的时候 SELECT语句的查询结果集 就会送到游标工作区 ,为后面游标的 逐条读取 结果集 中的记录做好准备。

打开游标的基本格式语法如下:

OPEN 游标名;

例如:打开我们前面创建的游标

OPEN cursor_emp;
OPEN cur_emp;

第三步:使用游标(从游标(结果集)中取得数据)

语法如下 :

FETCH 游标名 INTO 变量名1,变量名2.../*将游标结果集中的数据取出,并赋值到 变量1,变量2...当中
注意:变量需要在使用游标之前先定义声明好。*/

注意游标的查询结果集中的字段数,必须跟 INTO 赋值到的变量数一致,否侧,在执行的时候,MySQL会提示错误,尽量让变量的数据类型与 游标(查询的结果集)的数据类型一致,防止,赋值到的数据,出现错误,截断丢失的情况。

例如:我们将我们刚刚 定义的游标 cursor_emp 结果集数据取出

FETCH cursor_emp INTO emp_id ,emp_sal;

上述代码的作用是,使用 cursor_emp 这个游标来读取当前行,并且将数据保存到 emp_id,emp_sal 这两个变量中,游标指针直到下一行。如果游标读取的数据有多个列名,则在 INTO 关键字后面赋值给多个变量名即可。

注意:emp_id,emp_sal 变量必须在游标之前就定义好

第四步: 关闭游标

基本语法如下:

CLOSE 游标名 ; -- 关闭游标

OPEN(打开游标) 就有 CLOSE(关闭游标)

当我们使用完 游标 后需要关闭掉该游标,因为游标会占用 系统资源,如果不及时关闭,游标会一直保持到存储过程结束,影响系统运行的效率。而关闭游标的操作,会释放游标占用的系统资源。

关闭游标之后,我们就不能使用游标检索查询结果中的数据行,如果需要再次使用游标检索只能再次打开游标后,才能继续使用游标。

例如:关闭我们上述定义打开的游标

CLOSE cursor_emp;

3. 游标的使用案例

举例1: 创建存储过程“get_count_by_limit_total_salary()”,声明IN参数 limit_total_salary,DOUBLE类型;声明OUT参数total_count,INT类型。函数的功能可以实现累加薪资最高的几个员工的薪资值,直到薪资总和 达到limit_total_salary参数的值,返回累加的人数给total_count。

DELIMITER //
CREATE PROCEDURE get_count_by_limit_total_salary(IN limit_total_salary DOUBLE,OUT total_count INT)
BEGIN -- 声明局部变量,局部变量必须声明在begin...end最开始位置,不然报错DECLARE sum_sal DOUBLE DEFAULT 0.0;  -- 记录累加的工资总数DECLARE emp_sal DOUBLE DEFAULT 0.0 ;  -- 记录每个员工的工资DECLARE emp_count INT DEFAULT 0; -- 记录循环次数,必须default 设定默认初始值,不然为null,任何数-- 与 null 运算都为null,无法累加-- 1.声明定义游标DECLARE emp_cursor CURSOR FOR SELECT salaryFROM employees ORDER BY salary DESC; -- desc 降序-- 2.打开游标OPEN emp_cursor;-- 循环使用,游标REPEAT -- 3. 使用游标(取结果集中的数据,赋值到变量中去)FETCH emp_cursor INTO emp_sal;SET sum_sal = sum_sal + emp_sal;SET emp_count = emp_count + 1;UNTIL sum_sal >= limit_total_salary -- 满足条件,结束循环,不要加分号,不然报错END REPEAT; -- repeat 作用范围,结束SET total_count = emp_count;SELECT sum_sal; -- 查看局部变量 sum_sal 作用域在begin...end语句块中-- 关闭游标CLOSE emp_cursor;END //
DELIMITER ;

调用存储过程,如下

-- 调用存储过程
SET @total_count = 0; -- 定义会话变量,必须赋初始值
CALL get_count_by_limit_total_salary(200000,@total_count);


查看循环次数:

SELECT @total_count;


举例2: 创建存储过程 update_salary( ),参数为 IN 的int 类型的变量dep_id 表示部门id,参数2 为 in 的int类型变量。chang_sal_count,表示要调整薪资的员工的个数,查询指定id部门的员工信息,按照 salary 升序排列,根据 hire_date 的情况,调整前 change_sal_count 个员工的薪资,详情如下:

  • hire_date < 1995 ——> salary = salary * 1.2
  • hire_date >= 1995 and hire_date <= 1998 ——> salary = salary * 1.5
  • hire_date > 1998 and hire_date <= 2001 ——> salary = salary * 1.10
  • hire_date > 2001 ——> salary = salary * 1.05

先查询表,用于对比是否成功

SELECT employee_id,hire_date,salary
FROM employees
WHERE department_id = 50
ORDER BY salary ASC;

DELIMITER //
CREATE PROCEDURE update_salary(IN dept_id INT, IN change_sal_count INT)
BEGIN-- 声明局部变量,必须在begin...end最开始位置DECLARE emp_id INT; -- 记录员工idDECLARE emp_hire_date DATE; -- 记录员工入职时间DECLARE init_count INT DEFAULT 1; -- 表示循环结构,必须设定defaulte 默认初始值 不然为null,DECLARE add_sal_rate DOUBLE ; -- 记录涨薪的比例-- 1.声明游标(结果集)DECLARE emp_cursor CURSOR FOR SELECT employee_id,hire_date FROM employeesWHERE department_id = dept_id ORDER BY salary ASC ;-- asc 升序排序 -- 2.打开游标OPEN emp_cursor;-- 循环使用游标WHILE init_count <= change_sal_count DO -- 3. 使用游标(取出结果集中的数据,赋值到 变量中)FETCH emp_cursor INTO emp_id,emp_hire_date;  -- 尽量数据类型一致,防止存储错误,以及截断数据丢失-- 需要一一对应上,IF YEAR(emp_hire_date) < 1995THEN SET add_sal_rate = 1.2;ELSEIF YEAR(emp_hire_date) <= 1998 THEN SET add_sal_rate = 1.5;ELSEIF YEAR(emp_hire_date) <= 2001THEN SET add_sal_rate = 1.10;ELSE SET add_sal_rate = 1.05;END IF ; -- if 作用范围,结束    -- 涨薪操作UPDATE employeesSET salary = salary * add_sal_rateWHERE employee_id = emp_id;  SET init_count = init_count + 1;END WHILE; -- while 作用范围,结束-- 4.关闭游标CLOSE emp_cursor;END //
DELIMITER ;

调用存储过程,并查看验证结果

-- 调用存储过程
CALL update_salary(50,3);SELECT employee_id,hire_date,salary
FROM employees
WHERE department_id = 50
ORDER BY salary ASC;


4. 小结

游标是 MySQL 的一个重要的功能,为逐条读取结果集中的数据,提供了完美的解决方案。

跟应用层面,实现相同的功能相比,游标可以在存储程序中使用,效率高,程序也更加简洁。但同时也会带来一些性能问题,比如:在使用游标的过程中,会对数据行进行 加锁,这样在业务并发量大的时候,不仅会影响业务之间的效率,还会消耗系统资源,造成内存不足,这是因为游标是在内存中进行的处理。

强烈建议:养成用完之后就关闭的习惯,这样才能提高系统的整体效率

5. 最后:

限于自身水平,其中存在的错误,希望大家可以给予指教,韩信点兵——多多益善,谢谢大家,后会有期,江湖再见 !!!


MySQL 游标的详解相关推荐

  1. Mysql加锁过程详解(3)-关于mysql 幻读理解

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  2. mysql status改变_mysql 配置详解mysql SHOW STATUS 详解

    1. back_log 指定MySQL可能的连接数量.当MySQL主线程在很短的时间内得到非常多的连接请求,该参数就起作用,之后主线程花些时间(尽管很短)检查连接并且启动一个新线程. back_log ...

  3. MySQL 表分区详解MyiSam引擎和InnoDb 区别(实测)

    MySQL 表分区详解MyiSam引擎和InnoDb 区别(实测) 一.什么是表分区 通俗地讲表分区是将一大表,根据条件分割成若干个小表.mysql5.1开始支持数据表分区了. 如:某用户表的记录超过 ...

  4. Mysql存储引擎详解(MyISAM与InnoDB的区别)

    Mysql存储引擎详解(MyISAM与InnoDB的区别) 存储引擎     MySQL中的数据用各种不同的技术存储在文件(或者内存)中.这些技术中的每一种技术都使用不同的存储机制.索引技巧.锁定水平 ...

  5. MySQL的Limit详解(转载)

    MySQL的Limit详解 问题:数据库查询语句,如何只返回一部分数据? Top子句 TOP 子句用于规定要返回的记录的数目.对于拥有数千条记录的大型表来说,TOP 子句是非常有用的. 在SQL Se ...

  6. Mysql加锁过程详解(2)-关于mysql 幻读理解

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  7. 数据库mysql_row_MYSQL数据库mysql found_row()使用详解

    <MYSQL数据库mysql found_row()使用详解>要点: 本文介绍了MYSQL数据库mysql found_row()使用详解,希望对您有用.如果有疑问,可以联系我们. mys ...

  8. mysql 联合索引详解

    mysql 联合索引详解 联合索引又叫复合索引.对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分.例如索引是key index (a,b,c). ...

  9. MYSQL performance schema详解

    MYSQL performance schema详解 0.performance_schema的介绍 ​ MySQL的performance schema 用于监控MySQL server在一个较低级 ...

  10. shell编程系列23--shell操作数据库实战之mysql命令参数详解

    shell编程系列23--shell操作数据库实战之mysql命令参数详解mysql命令参数详解-u 用户名-p 用户密码-h 服务器ip地址-D 连接的数据库-N 不输出列信息-B 使用tab键代替 ...

最新文章

  1. 微型计算机m3500q,拆分式一体机!联想ThinkCentre 超级Q 23
  2. ARTS打卡计划第四周-ALGORITHM
  3. python学习三 函数
  4. Spring XML中如何使用 符号,比如数据库MySQL连接
  5. react(79)--ant design确认框
  6. Codeforces 990E Post Lamps 【暴力】【贪心】
  7. matlab重建算法stomp,压缩感知图像重建算法的研究现状及其展望.pdf
  8. 让lubuntu13.10中的virtualbox使用u盘
  9. 开源界也要封闭,OpenSource能否继续无国界 | 凌云时刻
  10. WORD VBA实现查找带格式的文字并复制到特定地方
  11. 如何将py文件转化为exe
  12. 常规通知(Notification)模板
  13. kibana远端访问配置
  14. OVN Southbound DB简介及其相关命令示例
  15. centos7 Kubeadm安装配置K8S 及Dashboard外部服务
  16. linux minicon usb配置,USB、Mini-USB、Micro-USB接口的引脚定义
  17. 计算机丢失UxTheme无法修复,Win7开机遇到uxtheme.dll丢失无法进入桌面怎么解决
  18. android 自定义图片裁剪,uCrop介绍,我们自己的安卓版图片裁剪库
  19. [渝粤教育] 武汉科技大学 创业基础(临班2106) 参考 资料
  20. 《Python数据分析与挖掘实战》第8章——Apriori关联规则

热门文章

  1. TypeError: Object of type ‘int64‘ is not JSON serializable
  2. CSS引用LCD 字体 简单倒计时功能
  3. 使用svnadmin对VisualSVN进行项目迁移
  4. cat more正常 vim显示中文乱码问题
  5. linux 注册并配置
  6. DC、HDC和CDC的区别及MFC常见类的作用
  7. 计算机应用实训任务与要求怎么写,计算机应用基础项目实训任务
  8. C++ ——Qt的信号和槽的详解
  9. C++随机数生成器(default_random_engine)
  10. INT 21H 指令说明及使用方法