1. 程式人生 > 資料庫 >mysql儲存過程遊標,計算儀器近期維保時間

mysql儲存過程遊標,計算儀器近期維保時間

mysql儲存過程遊標,計算儀器近期維保時間


最近工作遇到的問題,本來打算寫一個java api在外面計算維保時間然後新增到工單表中,後來發現數據量大的時候太慢了,程式會一直訪問資料庫。所以乾脆在內部寫,順便記錄下。

(1)mysql遊標簡單入門

概念就是在儲存過程中遍歷結果集。 以前我用分頁也實現過,現在看來,真是太蠢了。
遊標的使用方式:
1):建立遊標
declare <遊標名>CURSOR FOR select * from <表名>;
2):開啟遊標:
open <遊標名> ;
3):屬性賦值:
FETCH <遊標名字> into <變數名>;

例子:變數要在建立遊標前建立。
declare vUid int(11) default ‘0’;
declare <遊標名>CURSOR FOR select uid from <表名>;
FETCH <遊標名字> into vUid ;
這樣就可以賦值了。
4):關閉遊標
close mycursor;

(2)主題!根據儀器維保時間於維保規則建立近期維保工單。運用了些mysql函式這裡說一下。

now():獲取當天時間。
DATE_FORMAT(now() ,’%Y-%m-%d %H:%i:%s’):時間規則。
round():取整。
ADDDATE(‘時間’,interval <需新增天數>day);時間加法

to_days():時間轉換成天數,這個函式我老大說比較慢,資料量大的時候不建議用 。我還沒找到替代的函式。
if exists(select * from where)then :查詢通過判斷表中資料來判斷是否滿足if條件。


begin
	
-- 宣告所需賦值變數,這裡有個點需要說一下:宣告變數於宣告遊標之間不能對變數進行賦值。好像區域塊的原因具體我也不太清楚。
declare vUid int(11) default '0';
declare vDone int(11) default '0';
declare vDevcode varchar(100) default '';
declare vStartTime varchar(100) default '';
declare vEndTime varchar(100) default '';
declare vCreateTime varchar(100) default '';
declare vFirstDay int(11) default '0';
declare vRule varchar(100) default '';
declare vWeekPeriods varchar(100) default '';
declare vCustomCode varchar(100) default '';
declare vDefenId int(11) default '0';

declare vOverdueData varchar(100) default '';
declare vCon int(11) default '0';

-- 宣告遊標左聯出需要的資料。

declare mycursor CURSOR FOR select 
a.id ,
a.dev_number,
a.start_time ,
a.end_time ,
a.create_time ,
a.first_day ,
b.rule,
b.week_periods,
c.owner_customer_number 
from biosys_device_defenddate a
left join biosys_device_defend b on a.defcode_id = b.id 
left join bio_device c on a.dev_number = c.device_number ;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone=1;


-- 開啟遊標
open mycursor;
-- 這裡需要注意的點 into後面的需要賦值的值要與select查出的數量順序一致 不然無法進入迴圈體。
	FETCH  mycursor into vDefenId ,vDevcode ,vStartTime ,vEndTime ,vCreateTime ,vFirstDay ,vRule ,vWeekPeriods ,vCustomCode;
-- 下面這些的就是生成維保工單的邏輯演算法vFirstDay是資料表中取出維保日期偏移數值不能大於一週,所以這裡判斷取模。
	if vFirstDay>7 then
		set vFirstDay = 7%vFirstDay;
	end if ;
-- 進去遊標迴圈體這裡會把資料集迴圈出來。	
	while vDone<> 1 do
-- 判斷當天是否小於維保最後維保日期
		if DATE_FORMAT(now() ,'%Y-%m-%d %H:%i:%s')<DATE_FORMAT(vEndTime,'%Y-%m-%d %H:%i:%s')then
-- 開啟跳出迴圈 相當於java的break;要點必須包住while迴圈體
		outer_label:  BEGIN
-- 這裡根據維保規則計算還需維保幾次,結束時間減第一次維保時間除以維保週期,
--這要就可以算出需要維保的時間了,計算出的 vStartTime+偏移+維保週期 = 近期維保時間。
			while vCon < round((to_days(DATE_FORMAT(vEndTime,'%Y-%m-%d'))-to_days(DATE_FORMAT(vStartTime,'%Y-%m-%d')))/ (vWeekPeriods*7)) do
				set vOverdueData = date_format(ADDDATE(ADDDATE(date_format(vStartTime,'%Y-%m-%d'),interval vFirstDay day),interval vWeekPeriods*7 day),'%Y-%m-%d');
				if ROUND((to_days(DATE_FORMAT(vOverdueData,'%Y-%m-%d'))-to_days(DATE_FORMAT(now(),'%Y-%m-%d'))))<=7 then
				
					if exists(select a.pk_id from bio_device a where a.device_number = vDevcode)then 
							insert into biosys_workorder(`workorder_type_id`
								,`desc`,`memb_id`,`custom_id`
								,`title`,`code`,`create_date`
								,`exp_date`,`workerorder_bugtype_id`
								,`level`
								,`device_number`,`inspection`,`src_id`,`expected_date`,`ref_code`)
							values(5,'',1,vCustomCode
								,'裝置維保'
								,concat('BIO',_nextval('WO_ID'))
								,DATE_FORMAT(now() ,'%Y-%m-%d %H:%i:%s')
								,DATE_FORMAT( DATE_ADD(now(),INTERVAL 3 DAY)  ,'%Y-%m-%d')
								,1,1,vDevcode,'',4, DATE_FORMAT(vOverdueData ,'%Y-%m-%d %H:%i:%s')
								,0);
					end if ;
				else
					LEAVE  outer_label;
				end if ;
				set vCon = vCon+1;
				set vStartTime = vOverdueData;
			end while ;
		END outer_label; 
		end if;
	FETCH  mycursor into vDefenId,vDevcode ,vStartTime ,vEndTime ,vCreateTime ,vFirstDay ,vRule ,vWeekPeriods ,vCustomCode;
	end while ;
close mycursor;
	
END

到這裡就結束了。