mysql存儲(chǔ)過(guò)程多層游標(biāo)循環(huán)嵌套的寫法分享
mysql存儲(chǔ)過(guò)程多層游標(biāo)循環(huán)嵌套的寫法
最近有遇到一個(gè)需求
將有3級(jí)主從關(guān)聯(lián)的表數(shù)據(jù)同步到另外一個(gè)有3級(jí)主從關(guān)聯(lián)的表中,同步數(shù)據(jù)的表是第3級(jí)子表,而關(guān)聯(lián)關(guān)系在第1、2級(jí)主表中,由于考慮到到內(nèi)網(wǎng)數(shù)據(jù)庫(kù)可能沒法直接訪問(wèn)的限制,所以沒有用代碼來(lái)實(shí)現(xiàn),而是直接用存儲(chǔ)過(guò)程來(lái)實(shí)現(xiàn)
最終存儲(chǔ)過(guò)程的寫法如下
DELIMITER $$ USE `myDb`$$ DROP PROCEDURE IF EXISTS `syncBomSopFromRouteSop`$$ CREATE PROCEDURE `syncBomSopFromRouteSop`(IN tenantId BIGINT(11)) BEGIN ?? ?#工藝路線ID ?? ?DECLARE crId BIGINT(11); ?? ?#生產(chǎn)bomID ?? ?DECLARE pbrId BIGINT(11); ?? ?#工序檔案ID ?? ?DECLARE processId VARCHAR(50); ?? ?#生產(chǎn)bom工序Id ?? ?DECLARE bomProcessId BIGINT(11); ?? ?#生產(chǎn)bom數(shù)量 ?? ?DECLARE productionBomNum INT(5); ?? ?#生產(chǎn)bom工序數(shù)量 ?? ?DECLARE productionBomProcessNum INT(5); ?? ?DECLARE i INT(4) DEFAULT 1; ?? ?#DECLARE j INT(4) DEFAULT 1; ?? ?#定義生產(chǎn)bom游標(biāo) ?? ?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 /*測(cè)試1條數(shù)據(jù)AND pbr_id=86673*/? ?? ?); ?? ?#定義生產(chǎn)bom工序游標(biāo) ?? ?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 /*測(cè)試1條生產(chǎn)bom */ ?? ?); ?? ?#定義生產(chǎn)bom的sop游標(biāo) ?? ?/*DECLARE bomSopCursor CURSOR FOR ( ?? ?);*/ ?? ?#解決沒有查到數(shù)據(jù)報(bào):“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,'')<>''/*測(cè)試1條數(shù)據(jù) AND pbr_id=86673*/; ?? ?SET @creationDate=NOW(); ?? ?TRUNCATE TABLE a; ?? ?##打開生產(chǎn)bom游標(biāo) ?? ?OPEN productionBomCursor; ?? ??? ?/* 生產(chǎn)bom循環(huán)開始 */ ?? ??? ? 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層循環(huán) ?? ??? ? ? ?#打開生產(chǎn)bom工序游標(biāo) ?? ??? ? ? ?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'); ?? ??? ??? ??? ?#刪除生產(chǎn)bom工序下面的sop表記錄 ?? ??? ??? ??? ?UPDATE jgmes_modeling_production_sop SET delete_flag=1 WHERE tenant_id=tenantId AND delete_flag=0 AND pbp_id=bomProcessId; ?? ??? ??? ??? ?#將生產(chǎn)bom工序?qū)?yīng)工藝路線工序下面的sop文件復(fù)制插入 ?? ??? ??? ??? ?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; ?? ??? ??? ??? ?#游標(biāo)下移 ?? ??? ??? ??? ?FETCH bomProcessCursor INTO bomProcessId,processId; ?? ??? ??? ??? ?SET @j=@j+1; ?? ??? ??? ?END WHILE; ?? ??? ? ? ?CLOSE bomProcessCursor; ?? ??? ? ? ?#游標(biāo)下移 ?? ??? ? ? ?FETCH productionBomCursor INTO crId,pbrId; ?? ??? ? ? ?SET i=i+1; ?? ??? ? END WHILE; ?? ??? ?/*生產(chǎn)bom循環(huán)結(jié)束*/ ?? ?##關(guān)閉游標(biāo) ?? ?CLOSE productionBomCursor;?? ? ?? ?#返回新同步的數(shù)據(jù) ?? ?SELECT * FROM jgmes_modeling_production_sop WHERE tenant_id=tenantId AND delete_flag=0 AND creation_date=@creationDate AND created_by=-1; END$$ DELIMITER ;
剛開始寫完執(zhí)行時(shí),
報(bào)了一個(gè)“DECLARE CONTINUE HANDLER FOR NOT FOUND SET @IS_FOUND=0;”的錯(cuò)誤
后面加了如下語(yǔ)句就正常了:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET @IS_FOUND=0;
由于存儲(chǔ)過(guò)程調(diào)試不太方便,其中a表是用來(lái)調(diào)試用的臨時(shí)表,調(diào)試完成后可以刪除
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存儲(chǔ)過(guò)程循環(huán)中使用游標(biāo)方法及遇到的問(wèn)題
Oracle開發(fā)9年,頻繁使用存儲(chǔ)過(guò)程。現(xiàn)轉(zhuǎn)到mysql,使用存儲(chǔ)過(guò)程還是不太習(xí)慣,語(yǔ)法差別比較大,而且沒有深入去了解過(guò)mysql的存儲(chǔ)過(guò)程語(yǔ)法。
現(xiàn)在公司有部分?jǐn)?shù)據(jù)需要通過(guò)存儲(chǔ)過(guò)程處理,只能硬著頭皮上了。
循環(huán)
與oracle 用法基本一樣,使用loop或者while
首先定義一個(gè)游標(biāo)
DECLARE rs CURSOR FOR? ? SELECT ?? ??? ?contract_id ?? ?FROM ?? ??? ?data_sale_contract_delay ?? ?WHERE FLAG IS NULL or FLAG= '';
在游標(biāo)定義后面要定義一個(gè)如果游標(biāo)移動(dòng)到最后一行數(shù)據(jù)后再次移動(dòng)后處理的語(yǔ)句.
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1 ;
這個(gè)語(yǔ)句的含義是在fetch 不到內(nèi)容時(shí),將變量done 賦值為1.用來(lái)做跳出循環(huán)判斷用.
此處與Oracle不同,Oracle會(huì)更簡(jiǎn)單,直接exit when v_cur%notfound;就可以跳出循環(huán).v_cur是游標(biāo)的名字.
接下來(lái)打開游標(biāo),遍歷:
OPEN rs; FETCH NEXT FROM rs INTO v_contract_id; WHILE (done<>1) DO ?... ? ?-- 處理邏輯省略 ? FETCH NEXT FROM rs INTO v_contract_id;-- 處理完成后直接再?gòu)挠螛?biāo)讀取下一條數(shù)據(jù),如果已是最后一條數(shù)據(jù),再fetch時(shí)會(huì)出發(fā)上面的 CONTINUE HANDLER,將變量done 值改成1 END WHILE; CLOSE rs;
循環(huán)無(wú)法正常退出問(wèn)題
由于while中使用了select XX into XX from XXX的這種賦值語(yǔ)句在 select 的時(shí)候,沒查到數(shù)據(jù),導(dǎo)致出發(fā)handler將done修改為1,然后光標(biāo)就會(huì)跳出循環(huán)。
或者多層循環(huán)嵌套時(shí)內(nèi)循環(huán)出現(xiàn)將done修改為1的情況。
以上這兩種情況,都是因?yàn)镃ONTINUE HANDLER把done更新造成的,如果遇到此類問(wèn)題,需要在每次可能出現(xiàn)done被改變的地方處理完邏輯后增加set done=0;把變量值改一下,這樣就可以繼續(xù)執(zhí)行了。
總結(jié)
這些僅為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
避免MySQL中的隱式轉(zhuǎn)換的方法小結(jié)
在 MySQL 中,隱式轉(zhuǎn)換可能導(dǎo)致索引失效、結(jié)果不符合預(yù)期或性能問(wèn)題,以下是避免隱式轉(zhuǎn)換的具體方法,從表設(shè)計(jì)、查詢編寫到配置優(yōu)化,逐步減少隱式轉(zhuǎn)換的發(fā)生,具體操作過(guò)程跟隨小編一起看看吧2025-04-04
解決Windows環(huán)境下安裝 mysql-8.0.11-winx64 遇到的問(wèn)題
這篇文章主要介紹了Windows環(huán)境下安裝 mysql-8.0.11-winx64 遇到的問(wèn)題及解決辦法 ,需要的朋友可以參考下2018-10-10
MySQL 隨機(jī)查詢數(shù)據(jù)與隨機(jī)更新數(shù)據(jù)實(shí)現(xiàn)代碼
以下的文章主要講述的是MySQL隨機(jī)查詢數(shù)據(jù)、MySQL隨機(jī)更新數(shù)據(jù)的實(shí)際應(yīng)用以及對(duì)MySQL隨機(jī)查詢數(shù)據(jù)、MySQL隨機(jī)更新數(shù)據(jù)的實(shí)際應(yīng)用代碼的描述,以下就是文章的主要內(nèi)容描述,望你會(huì)有所收獲。2010-06-06
centos7中如何利用crontab進(jìn)行mysql定時(shí)備份
crontab是一個(gè)命令,常見于Unix和類Unix的操作系統(tǒng)之中,用于設(shè)置周期性被執(zhí)行的指令,下面這篇文章主要給大家介紹了關(guān)于centos7中如何利用crontab進(jìn)行mysql定時(shí)備份的相關(guān)資料,需要的朋友可以參考下2022-02-02
Mysql 5.6使用配置文件my.ini來(lái)設(shè)置長(zhǎng)時(shí)間連接數(shù)據(jù)庫(kù)的問(wèn)題
這篇文章主要介紹了Mysql 5.6使用配置文件my.ini來(lái)設(shè)置長(zhǎng)時(shí)間連接數(shù)據(jù)庫(kù),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07
MySQL 快速刪除大量數(shù)據(jù)(千萬(wàn)級(jí)別)的幾種實(shí)踐方案詳解
這篇文章主要介紹了MySQL 快速刪除大量數(shù)據(jù)(千萬(wàn)級(jí)別)的幾種實(shí)踐方案詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
10個(gè)提高M(jìn)ySQL安全性的重要措施:從賬號(hào)管理到網(wǎng)絡(luò)防護(hù),再到數(shù)據(jù)備份和版本更新
文章介紹了10個(gè)提高M(jìn)ySQL安全性的重要措施,包括賬號(hào)權(quán)限最小化、強(qiáng)制使用強(qiáng)密碼策略、禁用不必要的網(wǎng)絡(luò)端口、啟用SSL加密連接、定期備份數(shù)據(jù)、限制文件訪問(wèn)權(quán)限、禁用或限制不安全的SQL語(yǔ)句、啟用審計(jì)日志、定期更新MySQL版本以及使用Web應(yīng)用防火墻2026-03-03
在MySQL中實(shí)現(xiàn)冷熱數(shù)據(jù)分離的方法及使用場(chǎng)景底層原理解析
MySQL冷熱數(shù)據(jù)分離通過(guò)分表/分區(qū)策略、數(shù)據(jù)歸檔和索引優(yōu)化,將頻繁訪問(wèn)的熱數(shù)據(jù)與冷數(shù)據(jù)分開存儲(chǔ),提升查詢效率并降低存儲(chǔ)成本,適用于高并發(fā)交易、數(shù)據(jù)分析和日志管理等場(chǎng)景,感興趣的朋友跟隨小編一起看看吧2025-07-07

