最近有遇到一个需求:将有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