牧牛遛马
在大型的数据面前修改表内的内容,使用Mysql的游标实现
根据在存储过程的接触上实际的使用过程在代码的每个逻辑后面加上注释来大致实现一下遍历数据表的逻辑
踩过的雷区:
1、记不得游标的查询单词————–fetch
2、设置循环条件的代码写错————
declare continue handler for not found set flag = false;
漏写for,handler错写成handle
3、游标查询的时候要赋值给多个变量,加逗号就可以了
fetch liuma into lmage,lmname;
不能理解liuma里面有多条字段信息数据错误。
4、until 语句后面不能加逗号
正确———–until flag = false
错误———–until flag = false;
5、变量在游标或者handler的后面定义报错:
ERROR 1337 (42000): Variable or condition declaration after cursor or handler de
claration
Surfing the code…
提个需求:
更改表中的所有数据,规则如下
{
如果年龄大于18,名字后面加上说自己是成年人;
如果年龄小于18,名字后面加上说自己是未成年人;
}
1、先来一张表
这里便于演示,只显示了七条数据,根据实现的思想逻辑可以扩展到百万数据的更新。
mysql> select * from emp;
+----+--------+------+---------+
| id | name | age | dept_in |
+----+--------+------+---------+
| 1 | 张三 | 18 | 1 |
| 2 | 李四 | 18 | 1 |
| 3 | 王五 | 20 | 1 |
| 4 | 赵六 | 21 | 2 |
| 5 | 小强 | 12 | 3 |
| 6 | 大锤 | 12 | 3 |
| 7 | 中申通 | 23 | 3 |
+----+--------+------+---------+
7 rows in set (0.00 sec)
2、写一下游标遍历数据的代码
mysql> delimiter $$
mysql> create procedure muniu ()
-> begin
-> declare lmage int(11);
-> declare lmname varchar(50);
-> declare flag int default true;#声明一个开关变量flag用于循环结束判断默
认是true;
-> declare liuma cursor for(select age,name from emp);#申明一个游标,名
字叫liuma,因为游标指向的表内有两个字段,需要两个变量存储,所有得申明两个变量;
->
-> declare continue handler for not found set flag = false;
-> open liuma;#打开游标
->
-> repeat
-> fetch liuma into lmage,lmname;#把游标的内容赋值到变量中。
-> if(lmage<18)
-> then update emp set name = concat(lmname,"说我是未成年人,读
书少") where age = lmage;
-> elseif(lmage>18 or lmage = 18)
-> then update emp set name = concat(lmname,"说我是成年人,不会
乱来") where age = lmage;
-> end if;
-> until flag = false
-> end repeat;
-> close liuma;#关闭游标
-> end$$
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;
mysql>
mysql>
mysql>
mysql> call muniu;
Query OK, 0 rows affected (0.51 sec)
mysql> select * from emp;
+----+------------------------------+------+---------+
| id | name | age | dept_in |
+----+------------------------------+------+---------+
| 1 | 李四说我是成年人,不会乱来 | 18 | 1 |
| 2 | 李四说我是成年人,不会乱来 | 18 | 1 |
| 3 | 王五说我是成年人,不会乱来 | 20 | 1 |
| 4 | 赵六说我是成年人,不会乱来 | 21 | 2 |
| 5 | 大锤说我是未成年人,读书少 | 12 | 3 |
| 6 | 大锤说我是未成年人,读书少 | 12 | 3 |
| 7 | 中申通说我是成年人,不会乱来 | 23 | 3 |
+----+------------------------------+------+---------+
7 rows in set (0.00 sec)
从上面的代码运行中我们发现,当age重复的时候,他们的名字会出现错误,第一条应该是张三说,可是运行出来是李四说,第5条应该是小强说,运行出来是大锤说。
这是因为我们在查询的时候使用的是age字段,每次更新数据的时候会把age相同的一起更新,第二次把第一次覆盖导致。
要解决这个问题,需要在游标中传入一个主键参数,然后根据主键做条件,根据age做判断就可以解决。这里就先把数据更新为不重复数据,模拟age为主键的情况进行演示一下:
先更新一下数据
mysql> update emp set name = "张三" where id =1;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> update emp set age = 13 where id =1;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> update emp set name = "李四" where id= 2;
Query OK, 1 row affected (0.04 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> update emp set name = "王五" where id= 3;
Query OK, 1 row affected (0.05 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> update emp set name = "赵六" where id= 4;
Query OK, 1 row affected (0.04 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> update emp set name = "小强" where id= 5;
Query OK, 1 row affected (0.05 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> update emp set name = "大锤" where id= 6;
Query OK, 1 row affected (0.04 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> update emp set age=11 where id= 6;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> update emp set name = "中申通" where id= 7;
Query OK, 1 row affected (0.11 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from emp;
+----+--------+------+---------+
| id | name | age | dept_in |
+----+--------+------+---------+
| 1 | 张三 | 13 | 1 |
| 2 | 李四 | 18 | 1 |
| 3 | 王五 | 20 | 1 |
| 4 | 赵六 | 21 | 2 |
| 5 | 小强 | 12 | 3 |
| 6 | 大锤 | 11 | 3 |
| 7 | 中申通 | 23 | 3 |
+----+--------+------+---------+
7 rows in set (0.00 sec)
再运行一下游标过程存储:
mysql> delimiter $$
mysql> create procedure muniu ()
-> begin
-> declare lmage int(11);
-> declare lmname varchar(50);
-> declare flag int default true;
-> declare liuma cursor for select age,name from emp;
->
-> declare continue handler for not found set flag = false;
-> open liuma;
-> repeat
-> fetch liuma into lmage,lmname;
-> if(lmage<18)
-> then update emp set name = concat(lmname,"说我是未成年人,
读书少")
->
-> where age = lmage;
-> else
-> update emp set name = concat(lmname,"说我是成年人,不会乱
来") where
->
-> age = lmage;
-> end if;
->
-> until flag = false
-> end repeat;
-> close liuma;
-> end$$
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;
mysql>
mysql> call muniu;
Query OK, 0 rows affected (0.43 sec)
mysql> select * from emp;
+----+------------------------------+------+---------+
| id | name | age | dept_in |
+----+------------------------------+------+---------+
| 1 | 张三说我是未成年人,读书少 | 13 | 1 |
| 2 | 李四说我是成年人,不会乱来 | 18 | 1 |
| 3 | 王五说我是成年人,不会乱来 | 20 | 1 |
| 4 | 赵六说我是成年人,不会乱来 | 21 | 2 |
| 5 | 小强说我是未成年人,读书少 | 12 | 3 |
| 6 | 大锤说我是未成年人,读书少 | 11 | 3 |
| 7 | 中申通说我是成年人,不会乱来 | 23 | 3 |
+----+------------------------------+------+---------+
7 rows in set (0.00 sec)