mysql游标循环体内使用select into赋值会导致提前退出

MySQL游标与SELECT INTO
本文介绍MySQL存储过程中使用游标结合SELECT INTO时可能遇到的问题,特别是当未找到匹配记录时导致游标提前退出的情况。提供了三种解决方案:使用SET语句、COUNT函数以及手动重置循环结束标记。

       Mysql存储过程的游标循环体中使用“select  【某个字段】into 【某个变量】 from 【某个表】”语句进行 赋值, 如果 select 出来没有记录,则会导致游标提前退出(即使游标没有遍历完也会退出)。


表结构如下:

1.部门表以及相关数据

[sql]  view plain  copy
  1. <pre name="code" class="sql">create table department (  
  2.     id int unsigned not null auto_increment,  
  3.     name char(20) not null,  
  4.     primary key id  
  5. )engine=innobd default charset=utf8;  
  6.   
  7. insert department(id,namevalues(1,'技术部'),(2,'行政部'),(3,'人力部'),(4,'运营部'),(5,'财务部'),(6,'法务部'),(7,'市场部'),(8,'商务部'),(9,'客服部');  



2.员工表即相关数据

[sql]  view plain  copy
  1. <span style="font-family: Arial, Helvetica, sans-serif;"></span><pre name="code" class="sql">create table employee (  
  2.     id int unsigned not null auto_increment,  
  3.     name char(20) not null,  
  4.     entry_date date not null,  
  5.     department_id int unsigned not null,  
  6.     contrainst fk_employee_department foreign key(department_id) references    department(id) on delete on action on update on action  
  7. ) engine=innobd default charset=utf8;  
  8.   
  9. insert employee(id, name, department_id) values(1, '张三''2013-05-10',1),(2, '李四','2013-06-10',1),(3, '赵六','2013-05-10',2),(4, '薛七','2015-05-10',3),(5, '王麻子','2010-05-10',4),(6, '小六子','2013-08-10',5),(7, '赵云','2013-06-10',5),(8, '张飞','2013-10-10',5),(9, '关羽','2015-05-10',5),(10, '郭芙蓉','2013-01-10',9),(11, '凤姐','2012-05-10',9),(12, '芙蓉街','2013-01-10',9),(13, '魏延','2014-12-10',9),(14, '周瑜','2012-05-18',9),(15, '兵丁1','2014-03-10',9),(16, '王五','2016-01-10',2);  


比如有一个需求:部门表中要增加最近一次员工入职时间,并要求从员工表中找出每个部门中最近入职时间的员工入职时间设置到部门表中,如果有部门没有员工的话,则不管。

下面用存储过程实现,大概思路:先定义一个所有部门的游标,然后遍历此游标,根据游标中的部门id去员工表中查找最近一次入职的员工时间,存在的话,就更新部门记录。

代码如下:

[sql]  view plain  copy
  1. -- 部门表增加最近一次的员工入职时间字段  
[sql]  view plain  copy
  1. alter table department  
  2. add column last_employee_entry_date date default null after name;  
[sql]  view plain  copy
  1. -- 找到每个部门最近一次员工的入职时间,并更行部门表,如果部门不存在员工,则不更新  
  2. drop procedure pro_add_department_column if exists;  
  3. delimiter //  
  4. create procedure pro_add_department_column()  
  5. begin  
  6.     declare var_department_id int;  
  7.     declare var_last_entry_date date;  
  8.   
  9.     declare no_more int default 0;  
  10.   
  11.     declare cur_department cursor for  
  12.         select id from department;  
  13.           
  14.     declare continue handler for not found set no_more=1;  
  15.   
  16.     open cur_department  
  17.   
  18.     department_loop:LOOP  
  19.         fetch cur_department into var_department_id;  
  20.         if no_more = 1 then  
  21.             leave cur_department;  
  22.         end if;  
  23.   
  24.         select entry_date into var_last_entry_date from employee   
  25.             where department_id = var_department_id order by entry_date desc limit 0,1;  
  26.           
  27.         if var_last_entry_date is not null then   
  28.             update department set last_employee_entry_date = var_last_entry_date;  
  29.         end if;  
  30.           
  31.     end loop;  
  32.     close cur_department;  
  33. end; //  
  34.   
  35. delimiter ;   
  36.   
  37. call drop procedure pro_add_department_column;  
  38. drop procedure pro_add_department_column;  

在以上的代码中,如果有某个部门没有员工的话,游标就会直接退出,

原因是这个语句:select entry_date into var_last_entry_date from employee 
where department_id = var_department_id order by entry_date desc limit 0,1;

在游标使用select into语句进行赋值,如果select语句没有找到记录,则游标会直接退出!


所以为了防止遍历游标时,由于select into 导致游标提前退出,可以通过以下几种方法:

1. 采用set 赋值语句,比如上面的语句可以改成 set var_last_entry_date = (select entry_date from employee 
where department_id = var_department_id order by entry_date desc limit 0,1);

2.采用select count 语句,比如 select if (count(entry_date) > 0, entry_date, '') into var_last_entry_date from employee 
where department_id = var_department_id order by entry_date desc limit 0,1;

采用此方法的话,下面的判断条件if var_last_entry_date is not null 就需要与空字符串进行比较了,即改成if var_last_entry_date != '' then。

3. 因为当select· into赋值结果为null的时候,会自动修改循环触底的标志,所以手动在循环底部增加  set no_more = 0 这样也可以避免提前退出循环。

转载来自https://blog.youkuaiyun.com/rj042/article/details/51263287

### 回答1: MySQL 中的游标可以嵌套循环使用,实现比较复杂的数据处理逻辑。下面是一个简单的示例: ``` DECLARE cur1 CURSOR FOR SELECT id FROM table1; DECLARE cur2 CURSOR FOR SELECT value FROM table2 WHERE table1_id = @id; OPEN cur1; FETCH cur1 INTO @id; WHILE @@FETCH_STATUS = 0 DO OPEN cur2; FETCH cur2 INTO @value; WHILE @@FETCH_STATUS = 0 DO -- do something with @id and @value FETCH cur2 INTO @value; END WHILE; CLOSE cur2; FETCH cur1 INTO @id; END WHILE; CLOSE cur1; ``` 上面的代码中,先声明了两个游标 `cur1` 和 `cur2`,分别用于遍历表 `table1` 和表 `table2`。在第一个游标中,使用 `FETCH` 语句获取 `id`,并将其赋值给变量 `@id`。然后在 `WHILE` 循环中,检查 `@@FETCH_STATUS` 是否为 0,即是否还有数据可以获取。如果有,进入第二个游标循环使用 `@id` 来过滤 `table2` 中的数据,并使用 `FETCH` 语句获取 `value`,并将其赋值给变量 `@value`。在第二个游标循环中,同样检查 `@@FETCH_STATUS` 是否为 0,如果有,就可以对 `@id` 和 `@value` 进行处理。最后,关闭 `cur2` 游标,继续在第一个游标中获取下一个 `id`,直到所有数据都处理完毕。 需要注意的是,在使用游标嵌套循环时,要尽量避免使用过多的嵌套,以避免性能问题。同时,也要注意游标使用方式,确保在使用完毕后及时关闭游标,以释放资源。 ### 回答2: MySQL中的游标是一种用于遍历查询结果集的机制。游标嵌套循环是指在一个循环中嵌套另一个循环,并使用游标来控制内部循环的遍历过程。 在MySQL中,可以通过以下步骤来实现游标嵌套循环: 1. 声明外部循环游标:首先,需要声明一个外部循环游标,用于遍历外部查询的结果集。 2. 打开外部循环游标:在开始外部循环之前,需要使用OPEN语句打开外部游标,准备开始遍历外部结果集。 3. 声明内部循环游标:在外部循环内部,需要声明一个内部循环游标,用于遍历内部查询的结果集。 4. 打开内部循环游标:在开始内部循环之前,需要使用OPEN语句打开内部游标,准备开始遍历内部结果集。 5. 循环遍历内部结果集:在内部循环使用FETCH语句来从内部游标中获取一行结果,并进行相应的处理。 6. 关闭内部循环游标:在内部循环结束后,使用CLOSE语句来关闭内部游标,释放资源。 7. 关闭外部循环游标:在外部循环结束后,使用CLOSE语句来关闭外部游标,释放资源。 通过以上步骤,可以实现游标嵌套循环的功能。在嵌套循环中,外部循环的每一次迭代都会执行内部循环的全部迭代,直到外部循环结束。这种方法可以用于处理需要对多个结果集进行复杂操作的情况,提供了一种灵活的查询和处理方式。 需要注意的是,游标嵌套循环可能会导致性能问题,特别是在处理大数据量时。因此,在使用游标嵌套循环时,应谨慎使用,并根据实际情况考虑其他更高效的处理方式。 ### 回答3: MySQL中的游标嵌套循环是指在一个游标内部嵌套了另一个游标,并通过循环来处理嵌套的游标游标是一种数据库对象,用于从查询结果中逐行获取数据。在MySQL中,使用游标需要以下步骤: 1. 声明并定义游标:通过DECLARE语句来声明和定义游标,可以指定游标的名称、查询语句和其他属性。 2. 打开游标使用OPEN语句来打开游标,使其准备好获取数据。 3. 循环获取数据:使用FETCH语句来逐行获取游标所指向的查询结果数据。可以通过循环的方式获取所有数据或者仅获取所需的数据。 4. 关闭游标使用CLOSE语句来关闭游标,释放资源。 在游标嵌套循环中,内层游标的查询依赖于外层游标的结果。嵌套循环的步骤如下: 1. 声明并定义外层游标。 2. 打开外层游标。 3. 循环获取外层游标的数据。 4. 在外层循环中,声明并定义内层游标,并将内层游标的查询条件绑定到外层游标的数据。 5. 打开内层游标。 6. 循环获取内层游标的数据。 7. 关闭内层游标。 8. 关闭外层游标。 通过游标嵌套循环可以在多个数据集之间进行关联操作。对于每个外层数据,内层循环可以获取相关的数据进行处理。嵌套循环可以用于完成复杂的数据处理和逻辑操作,但是需要注意效率和性能的问题,因为每次循环都需要执行数据库操作,可能会导致性能下降。 总之,MySQL中的游标嵌套循环是一种处理复杂数据操作的方法,通过嵌套的方式将多个数据集关联起来,可以提高数据处理的灵活性和精确性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值