mysql存储过程多层游标循环嵌套的写法分享

 更新时间:2023年07月06日 10:16:42   作者:LT_1029  
这篇文章主要介绍了mysql存储过程多层游标循环嵌套的写法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

mysql存储过程多层游标循环嵌套的写法

最近有遇到一个需求

将有3级主从关联的表数据同步到另外一个有3级主从关联的表中,同步数据的表是第3级子表,而关联关系在第1、2级主表中,由于考虑到到内网数据库可能没法直接访问的限制,所以没有用代码来实现,而是直接用存储过程来实现

最终存储过程的写法如下

DELIMITER $$
USE `myDb`$$
DROP PROCEDURE IF EXISTS `syncBomSopFromRouteSop`$$
CREATE PROCEDURE `syncBomSopFromRouteSop`(IN tenantId BIGINT(11))
BEGIN
    #工艺路线ID
    DECLARE crId BIGINT(11);
    #生产bomID
    DECLARE pbrId BIGINT(11);
    #工序档案ID
    DECLARE processId VARCHAR(50);
    #生产bom工序Id
    DECLARE bomProcessId BIGINT(11);
    #生产bom数量
    DECLARE productionBomNum INT(5);
    #生产bom工序数量
    DECLARE productionBomProcessNum INT(5);
    DECLARE i INT(4) DEFAULT 1;
    #DECLARE j INT(4) DEFAULT 1;
    #定义生产bom游标
    DECLARE productionBomCursor CURSOR FOR (
        SELECT cr_id,pbr_id FROM jgmes_modeling_production_bom_route WHERE tenant_id=tenantId AND delete_flag=0 AND IFNULL(cr_id,'')<>'' ORDER BY cr_id,pbr_id /*测试1条数据AND pbr_id=86673*/ 
    );
    #定义生产bom工序游标
    DECLARE bomProcessCursor CURSOR FOR (
        SELECT pbp_id bomProcessId,p.p_id processId
        FROM jgmes_modeling_production_bom_process pbp 
        LEFT JOIN jgmes_modeling_process p ON p.p_id=pbp.p_id
        LEFT JOIN jgmes_modeling_production_bom_route pbr ON pbr.pbr_id=pbp.pbr_id
        WHERE pbp.tenant_id=tenantId AND pbp.delete_flag=0 AND 
        pbr.tenant_id=tenantId AND pbr.delete_flag=0 AND pbr.pbr_id=pbrId /*测试1条生产bom */
    );
    #定义生产bom的sop游标
    /*DECLARE bomSopCursor CURSOR FOR (
    );*/
    #解决没有查到数据报:“DECLARE CONTINUE HANDLER FOR NOT FOUND SET @IS_FOUND=0;”的异常的处理方法
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET @IS_FOUND=0;
    SELECT COUNT(*) INTO productionBomNum FROM jgmes_modeling_production_bom_route WHERE tenant_id=tenantId AND delete_flag=0 AND IFNULL(cr_id,'')<>''/*测试1条数据 AND pbr_id=86673*/;
    SET @creationDate=NOW();
    TRUNCATE TABLE a;
    ##打开生产bom游标
    OPEN productionBomCursor;
        /* 生产bom循环开始 */
         FETCH productionBomCursor INTO crId,pbrId;
         WHILE i<=productionBomNum DO
            SELECT COUNT(*) INTO productionBomProcessNum FROM jgmes_modeling_production_bom_process WHERE tenant_id=tenantId AND delete_flag=0 AND pbr_id=pbrId;
            #第2层循环
            #打开生产bom工序游标
            OPEN bomProcessCursor;
            FETCH bomProcessCursor INTO bomProcessId,processId;
            SET @j=1;  
            WHILE @j<=productionBomProcessNum DO
            INSERT INTO a (seqNum, remark)VALUES(CONCAT(i,'_',@j,'_',bomProcessId), 'i-j-bomProcessId');
                #INSERT INTO a (seqNum, remark)VALUES(CONCAT(crId,'_',processId), 'crProcessId');
                #删除生产bom工序下面的sop表记录
                UPDATE jgmes_modeling_production_sop SET delete_flag=1 WHERE tenant_id=tenantId AND delete_flag=0 AND pbp_id=bomProcessId;
                #将生产bom工序对应工艺路线工序下面的sop文件复制插入
                INSERT INTO jgmes_modeling_production_sop (
                  pbr_id,
                  pbp_id,
                  sn,
                  file_name,
                  file_path,
                  file_type,
                  file_length,
                  file_version_num,
                  tenant_id,
                  creation_date,
                  created_by,
                  last_update_date,
                  last_updated_by,
                  last_update_login,
                  delete_flag,
                  version_num
                )
                SELECT
                  pbrId,
                  bomProcessId,
                  sn,
                  file_name,
                  file_path,
                  file_type,
                  file_length,
                  file_version_num,
                  sop.tenant_id,
                  @creationDate,
                  -1,
                  sop.last_update_date,
                  sop.last_updated_by,
                  sop.last_update_login,
                  sop.delete_flag,
                  sop.version_num
                FROM
                  jgmes_modeling_crafts_sop  sop
                LEFT JOIN jgmes_modeling_crafts_process cp ON cp.cp_id=sop.cp_id
                LEFT JOIN jgmes_modeling_process p ON p.p_id=cp.p_id
                WHERE sop.tenant_id=tenantId AND sop.delete_flag=0 AND cp.cr_id=crId AND cp.p_id=processId;
                #游标下移
                FETCH bomProcessCursor INTO bomProcessId,processId;
                SET @j=@j+1;
            END WHILE;
            CLOSE bomProcessCursor;
            #游标下移
            FETCH productionBomCursor INTO crId,pbrId;
            SET i=i+1;
         END WHILE;
        /*生产bom循环结束*/
    ##关闭游标
    CLOSE productionBomCursor;    
    #返回新同步的数据
    SELECT * FROM jgmes_modeling_production_sop WHERE tenant_id=tenantId AND delete_flag=0 AND creation_date=@creationDate AND created_by=-1;
END$$
DELIMITER ;

刚开始写完执行时,

报了一个“DECLARE CONTINUE HANDLER FOR NOT FOUND SET @IS_FOUND=0;”的错误

后面加了如下语句就正常了:

DECLARE CONTINUE HANDLER FOR NOT FOUND SET @IS_FOUND=0;

由于存储过程调试不太方便,其中a表是用来调试用的临时表,调试完成后可以删除

CREATE TABLE `a` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `seqNum` varchar(50) DEFAULT NULL,
  `remark` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10722 DEFAULT CHARSET=utf8mb4

mysql存储过程循环中使用游标方法及遇到的问题

Oracle开发9年,频繁使用存储过程。现转到mysql,使用存储过程还是不太习惯,语法差别比较大,而且没有深入去了解过mysql的存储过程语法。

现在公司有部分数据需要通过存储过程处理,只能硬着头皮上了。

循环

与oracle 用法基本一样,使用loop或者while

首先定义一个游标

DECLARE rs CURSOR FOR 
  SELECT
        contract_id
    FROM
        data_sale_contract_delay
    WHERE FLAG IS NULL or FLAG= '';

在游标定义后面要定义一个如果游标移动到最后一行数据后再次移动后处理的语句.

DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1 ;

这个语句的含义是在fetch 不到内容时,将变量done 赋值为1.用来做跳出循环判断用.

此处与Oracle不同,Oracle会更简单,直接exit when v_cur%notfound;就可以跳出循环.v_cur是游标的名字.

接下来打开游标,遍历:

OPEN rs;
FETCH NEXT FROM rs INTO v_contract_id;
WHILE (done<>1) DO
 ...    -- 处理逻辑省略
  FETCH NEXT FROM rs INTO v_contract_id;-- 处理完成后直接再从游标读取下一条数据,如果已是最后一条数据,再fetch时会出发上面的 CONTINUE HANDLER,将变量done 值改成1
END WHILE;
CLOSE rs;

循环无法正常退出问题

由于while中使用了select XX into XX from XXX的这种赋值语句在 select 的时候,没查到数据,导致出发handler将done修改为1,然后光标就会跳出循环。

或者多层循环嵌套时内循环出现将done修改为1的情况。

以上这两种情况,都是因为CONTINUE HANDLER把done更新造成的,如果遇到此类问题,需要在每次可能出现done被改变的地方处理完逻辑后增加set done=0;把变量值改一下,这样就可以继续执行了。

总结

这些仅为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • MySQL备份与恢复之热拷贝(4)

    MySQL备份与恢复之热拷贝(4)

    热拷贝支持服务运行中进行备份,速度快,性能好,但它的劣势在于只能备份MyIsam的表,无法备份InnoDB的表,对热拷贝感兴趣的朋友可以参考一下这篇文章
    2015-08-08
  • MySQL中大数据表增加字段的实现思路

    MySQL中大数据表增加字段的实现思路

    最近遇到的一个问题,需要在一张将近1000万数据量的表中添加加一个字段,但是直接添加会导致mysql 奔溃,所以需要利用其他的方法进行添加,这篇文章主要给大家介绍了MySQL中大数据表增加字段的实现思路,需要的朋友可以参考借鉴。
    2017-01-01
  • 教你用eclipse连接mysql数据库

    教你用eclipse连接mysql数据库

    这篇文章主要介绍了教你用eclipse连接mysql数据库,文中有非常详细的图文示例,对不会链接mysql的小伙伴们有很大的帮助,需要的朋友可以参考下
    2021-04-04
  • MySQL 使用DQL命令查询数据的实现方法

    MySQL 使用DQL命令查询数据的实现方法

    这篇文章主要介绍了MySQL 使用DQL命令查询数据的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • MySQL sleep函数使用方法详解

    MySQL sleep函数使用方法详解

    sleep函数时「延时」指定时间(单位秒),也就是让程序停止执行一段指定的时间,本文就给大家简单的介绍一下MySQL sleep函数使用方法,需要的朋友可以参考下
    2023-07-07
  • mysql 5.7.14 安装配置简单教程

    mysql 5.7.14 安装配置简单教程

    这篇文章主要为大家分享了mysql 5.7.14安装配置方法图文教程,一看就会的mysql 5.7.14安装教程,感兴趣的朋友可以参考一下
    2016-08-08
  • 基于Mysql的Sequence实现方法

    基于Mysql的Sequence实现方法

    下面小编就为大家带来一篇基于Mysql的Sequence实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • MySQL 编码utf8 与 utf8mb4 utf8mb4_unicode_ci 与 utf8mb4_general_ci

    MySQL 编码utf8 与 utf8mb4 utf8mb4_unicode_ci 与 utf8mb4_general_

    这篇文章主要介绍了MySQL 编码utf8 与 utf8mb4 utf8mb4_unicode_ci 与 utf8mb4_general_ci的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • mysql过滤复制思路详解

    mysql过滤复制思路详解

    这篇文章主要介绍了mysql过滤复制的实现思路,主要讲解了两种思路,一种是在主库的binlog上实现另一种是从库的sql线程上实现,具体实现过程跟随小编一起看看吧
    2021-08-08
  • 一次Mysql使用IN大数据量的优化记录

    一次Mysql使用IN大数据量的优化记录

    这篇文章主要给大家介绍了关于Mysql使用IN大数据量的优化的实战记录,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09

最新评论