mysql存儲(chǔ)過程多層游標(biāo)循環(huán)嵌套的寫法分享
mysql存儲(chǔ)過程多層游標(biāo)循環(huán)嵌套的寫法
最近有遇到一個(gè)需求
將有3級主從關(guān)聯(lián)的表數(shù)據(jù)同步到另外一個(gè)有3級主從關(guān)聯(lián)的表中,同步數(shù)據(jù)的表是第3級子表,而關(guān)聯(lián)關(guān)系在第1、2級主表中,由于考慮到到內(nèi)網(wǎng)數(shù)據(jù)庫可能沒法直接訪問的限制,所以沒有用代碼來實(shí)現(xiàn),而是直接用存儲(chǔ)過程來實(shí)現(xiàn)
最終存儲(chǔ)過程的寫法如下
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 /*測試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 /*測試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,'')<>''/*測試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ò)誤
后面加了如下語句就正常了:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET @IS_FOUND=0;
由于存儲(chǔ)過程調(diào)試不太方便,其中a表是用來調(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ǔ)過程循環(huán)中使用游標(biāo)方法及遇到的問題
Oracle開發(fā)9年,頻繁使用存儲(chǔ)過程。現(xiàn)轉(zhuǎn)到mysql,使用存儲(chǔ)過程還是不太習(xí)慣,語法差別比較大,而且沒有深入去了解過mysql的存儲(chǔ)過程語法。
現(xiàn)在公司有部分?jǐn)?shù)據(jù)需要通過存儲(chǔ)過程處理,只能硬著頭皮上了。
循環(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)后處理的語句.
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1 ;
這個(gè)語句的含義是在fetch 不到內(nèi)容時(shí),將變量done 賦值為1.用來做跳出循環(huán)判斷用.
此處與Oracle不同,Oracle會(huì)更簡單,直接exit when v_cur%notfound;就可以跳出循環(huán).v_cur是游標(biāo)的名字.
接下來打開游標(biāo),遍歷:
OPEN rs; FETCH NEXT FROM rs INTO v_contract_id; WHILE (done<>1) DO ?... ? ?-- 處理邏輯省略 ? FETCH NEXT FROM rs INTO v_contract_id;-- 處理完成后直接再從游標(biāo)讀取下一條數(shù)據(jù),如果已是最后一條數(shù)據(jù),再fetch時(shí)會(huì)出發(fā)上面的 CONTINUE HANDLER,將變量done 值改成1 END WHILE; CLOSE rs;
循環(huán)無法正常退出問題
由于while中使用了select XX into XX from XXX的這種賦值語句在 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更新造成的,如果遇到此類問題,需要在每次可能出現(xiàn)done被改變的地方處理完邏輯后增加set done=0;把變量值改一下,這樣就可以繼續(xù)執(zhí)行了。
總結(jié)
這些僅為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
mysql 5.7.17 以及workbench安裝配置圖文教程
這篇文章主要為大家詳細(xì)介紹了mysql 5.7.17 以及workbench安裝配置圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06Mysql數(shù)據(jù)庫時(shí)間與系統(tǒng)時(shí)間不一致問題排查及解決
最近忽然發(fā)現(xiàn)個(gè)問題,Mysql數(shù)據(jù)庫時(shí)間與系統(tǒng)時(shí)間不一致,通過查找相關(guān)資料終于解決了,下面這篇文章主要給大家介紹了關(guān)于Mysql數(shù)據(jù)庫時(shí)間與系統(tǒng)時(shí)間不一致問題排查及解決的相關(guān)資料,需要的朋友可以參考下2023-06-06mysql數(shù)據(jù)庫navicat數(shù)據(jù)同步時(shí)誤刪除部分?jǐn)?shù)據(jù)的解決
本文主要介紹了mysql數(shù)據(jù)庫navicat數(shù)據(jù)同步時(shí)誤刪除部分?jǐn)?shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-04-04MySQL如何將一個(gè)表的字段更新到另一個(gè)表中
在數(shù)據(jù)庫管理中,經(jīng)常需要將一個(gè)表中的數(shù)據(jù)更新到另一個(gè)表中,本文將通過幾個(gè)簡單示例為大家詳細(xì)介紹如何在MySQL中實(shí)現(xiàn)這一功能,有需要的可以參考下2025-01-01MySQL中Innodb的事務(wù)隔離級別和鎖的關(guān)系的講解教程
這篇文章主要介紹了MySQL中Innodb的事務(wù)隔離級別和鎖的關(guān)系講解教程,來自于美團(tuán)技術(shù)團(tuán)隊(duì)的經(jīng)驗(yàn)實(shí)際經(jīng)驗(yàn)分享,需要的朋友可以參考下2015-11-11使用squirrel進(jìn)行sql拼接不生效問題及解決
這篇文章主要介紹了使用squirrel進(jìn)行sql拼接不生效問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09MySQL中查詢某一天, 某一月, 某一年的數(shù)據(jù)代碼詳解
本文通過實(shí)例代碼給大家介紹了MySQL中, 如何查詢某一天, 某一月, 某一年的數(shù)據(jù) ,需要的朋友可以參考下2019-06-06