1. 程式人生 > >Mysql procedure原理、語法 、例項

Mysql procedure原理、語法 、例項

Mysql儲存過程是一組為了完成特定功能的SQL語句集,經過編譯之後儲存在資料庫中,當需要使用該組SQL語句時使用者只需要通過指定儲存過程的名字並給定引數就可以呼叫執行它了。 業務邏輯可以封裝儲存過程中,這樣不僅容易維護,而且執行效率也高。

一、Mysql儲存過程簡介:
儲存過程是一個可程式設計的函式,它在資料庫中建立並儲存。它可以有SQL語句和一些特殊的控制結構組成。當希望在不同的應用程式或平臺上執行相同的函式,或者封裝特定功能時,儲存過程是非常有用的。資料庫中的儲存過程可以看做是對程式設計中面向物件方法的模擬。它允許控制資料的訪問方式。儲存過程通常有以下優點:

1)儲存過程能實現較快的執行速度。


如果某一操作包含大量的Transaction-SQL程式碼或分別被多次執行,那麼儲存過程要比批處理的執行速度快很多。因為儲存過程是預編譯的。在首次執行一個儲存過程時查詢,優化器對其進行分析優化,並且給出最終被儲存在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次執行時都要進行編譯和優化,速度相對要慢一些。

2)儲存過程允許標準組件是程式設計。
儲存過程被建立後,可以在程式中被多次呼叫,而不必重新編寫該儲存過程的SQL語句。而且資料庫專業人員可以隨時對儲存過程進行修改,對應用程式原始碼毫無影響。

3)儲存過程可以用流控制語句編寫,有很強的靈活性,可以完成複雜的判斷和較複雜的運算



4)儲存過程可被作為一種安全機制來充分利用。
系統管理員通過執行某一儲存過程的許可權進行限制,能夠實現對相應的資料的訪問許可權的限制,避免了非授權使用者對資料的訪問,保證了資料的安全。

5)儲存過程能過減少網路流量。
針對同一個資料庫物件的操作(如查詢、修改),如果這一操作所涉及的Transaction-SQL語句被組織程儲存過程,那麼當在客戶計算機上呼叫該儲存過程時,網路中傳送的只是該呼叫語句,從而大大增加了網路流量並降低了網路負載。

二、儲存程式中的變數
1)DECLARE區域性變數
DECLARE var_name[,...] type [DEFAULT value]
這個語句被用來宣告區域性變數。

要給變數提供一個預設值,請包含一個DEFAULT子句。值可以被指定為一個表示式,不需要為一個常數。如果沒有DEFAULT子句,初始值為NULL。 區域性變數的作用範圍在它被宣告的BEGIN ... END塊內。它可以被用在巢狀的塊中,除了那些用相同名字宣告變數的塊。
2)變數SET語句
SET var_name = expr [, var_name = expr] 
在儲存程式中的SET語句是一般SET語句的擴充套件版本。
被參考變數可能是子程式內宣告的變數,或者是全域性伺服器變數。 在儲存程式中的SET語句作為預先存在的SET語法的一部分來實現。這允許SET a=x, b=y, ...這樣的擴充套件語法。其中不同的變數型別(局域宣告變數及全域性和集體變數)可以被混合起來。這也允許把區域性變數和一些只對系統變數有意義的選項合併起來。
3)SELECT ... INTO 語句
SELECT col_name[,...] INTO var_name[,...] table_expr
這個SELECT語法把選定的列直接儲存到變數。因此,只有單一的行可以被取回。 SELECT id,data INTO x,y FROM test.t1 LIMIT 1;

三、下面來看一個mysql 儲存過程的完整例項。

BEGIN 


DECLARE customerId Long;#客戶ID 
DECLARE totalBuy LONG;#當前購買產品數 
DECLARE cumTotalBuy LONG;#累計購買產品數 
DECLARE redemptionPro LONG;#已到期贖回產品數 
DECLARE expiredPro LONG;#當天到期產品數 
DECLARE witAmount double(18,6) DEFAULT 0;#申請提現金額 
  DECLARE assetsid long; 

## DECLARE reqredeemAmount double(18,6) ;#申請贖回金額 
DECLARE reqredeemPro LONG;#申請贖回數量 
DECLARE done INT DEFAULT 0;#遊標執行識別符號 
DECLARE buyRecordId LONG;#客戶購買記錄ID 
DECLARE v_err_op VARCHAR(1); #異常資訊識別符號 
DECLARE v_err_msg VARCHAR(255); #錯誤資訊
DECLARE cur_buyRecord  cursor  for  select customer.id,customer.BUY_RECORD_ID,ASSETS_ID from T_CUSTOM customer,T_BIND_BANK custbank  
                                            where customer.BIND_BANK_ID  = custbank.ID ; 
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 


open cur_buyRecord; 

loop_curBuyRecord:loop 

FETCH cur_buyRecord INTO customerId,buyRecordId,assetsid; 


if done=1 then  

leave loop_curBuyRecord;  
end if; 
##########################################當前購買產品數########################################################### 

SELECT IFNULL(COUNT(*),0) INTO totalBuy FROM T_TRAN_RECORDS WHERE TRADE_TYPE='CUSTOMBOUGHY' AND CUSTOM_ID=customerId; 

##########################################累計購買產品數########################################################### 

SELECT IFNULL(COUNT(*),0) INTO cumTotalBuy FROM T_TRAN_RECORDS WHERE ( TRADE_TYPE='CUSTOMBOUGHY' OR  TRADE_TYPE='CUSTOMERREQREDEEM' or  TRADE_TYPE='CUSTOMERREDEEM') AND CUSTOM_ID=customerId; 

##########################################已到期贖回產品數########################################################### 

SELECT IFNULL(COUNT(*),0) INTO redemptionPro FROM T_TRAN_RECORDS WHERE TRADE_TYPE='CUSTOMERREDEEM' AND CUSTOM_ID=customerId; 

##########################################當天到期產品數########################################################### 

SELECT IFNULL(COUNT(*),0) INTO expiredPro FROM T_TRAN_RECORDS tran,T_PRODUCT p WHERE p.PROD_TYPE_ID = 1 and p.DEADLIME=To_Days(NOW())-To_Days(tran.OCC_DATE) and tran.PRODUCT_ID=p.ID and tran.CUSTOM_ID =customerId and tran.TRADE_TYPE='CUSTOMBOUGHY'; 

##########################################申請提現金額############################################################# 

SELECT SUM(IFNULL(TRADE_AMOUNT,0)) INTO witAmount FROM T_TRAN_RECORDS WHERE  TRADE_TYPE='CUSTOMERREQWITHDRAW' AND CUSTOM_ID=customerId  and ( WITHDRAWFLAG = '0'  or WITHDRAWFLAG is null ) ; 

                        ##########################################申請贖回金額##################################################### 

##SELECT SUM(IFNULL(TRADE_AMOUNT,0)) INTO reqredeemAmount FROM T_TRAN_RECORDS WHERE  TRADE_TYPE='CUSTOMERREQREDEEM' AND CUSTOM_ID=customerId; 

##########################################申請贖回數量########################################## 

SELECT IFNULL(COUNT(*),0) INTO reqredeemPro FROM T_TRAN_RECORDS WHERE TRADE_TYPE='CUSTOMERREQREDEEM' AND CUSTOM_ID=customerId; 


###################################################witAmount如果交易表中狀態是提現 ,那麼  資材表的 閒置金額 以及總資產 減去 提現金額 
  if  witAmount > 0 then 
update  T_CUSTOM_ASSETS set TOTAL_AMOUNT = TOTAL_AMOUNT - witAmount ,ASSETS_AMOUNT = ASSETS_AMOUNT - witAmount 
  where     T_CUSTOM_ASSETS.ID = assetsid ; 

  update  T_TRAN_RECORDS  set T_TRAN_RECORDS.WITHDRAWFLAG = '1'   WHERE  T_TRAN_RECORDS.TRADE_TYPE='CUSTOMERREQWITHDRAW' AND T_TRAN_RECORDS.CUSTOM_ID=customerId; 

  end if; 



###################################################### 

#驗證使用者購買記錄資訊是否存在 

if ISNULL( expiredPro) THEN 
SET expiredPro=0; 

END IF; 

if ISNULL( witAmount) THEN 
SET witAmount=0; 
END IF; 
/* 
if ISNULL( reqredeemAmount) THEN 
SET reqredeemAmount=0; 
END IF; 
*/ 

if ISNULL(buyRecordId) THEN 

set v_err_msg = 'insert'; 

INSERT into T_CUSTOM_BUY_RECORD(TOTAL_BUY,CUM_TOTAL_BUY,REDEMPTION_PRO,EXPIRED_PRO,WIT_AMOUNT,REQREDEEM_PRO,UPDATE_DATE)
VALUES(totalBuy,cumTotalBuy,redemptionPro,expiredPro,witAmount,reqredeemPro,NOW()); 



SELECT max(id) into buyRecordId from T_CUSTOM_BUY_RECORD; 

UPDATE T_CUSTOM SET BUY_RECORD_ID=buyRecordId where ID = customerId; 

ELSE 

set v_err_msg = 'update'; 

UPDATE T_CUSTOM_BUY_RECORD set TOTAL_BUY=totalBuy, 
CUM_TOTAL_BUY=cumTotalBuy, 
REDEMPTION_PRO=redemptionPro, 
EXPIRED_PRO=expiredPro, 
WIT_AMOUNT=witAmount, 
REQREDEEM_PRO=reqredeemPro, 
UPDATE_DATE=NOW() 
where ID=buyRecordId; 
END IF; 

commit; 
END  loop; 

CLOSE cur_buyRecord; 

END

寫一個定時器呼叫這個儲存過程,定時執行運算,就可以達到想要的效果了。