需求:
有三張表:Player、Consumption、Consumption_other。Player表中記錄用戶信息(playerid、origin等字段),Consumption和Consumption_other記錄用戶的消費信息。現需要根據Player表中的origin字段,分別向Consumption和Consumption_other表中插入一條消費記錄。規定:Player表中origin=0的,將信息插入到Consumption表中;Player表中origin不爲0的,將信息插入到Consumption_other表中。
方法:
使用MySQL的存儲過程和遊標實現:
mysql> DELIMITER // mysql> CREATE PROCEDURE `add_consumption`() -> BEGIN -> -- 定義需要接收遊標數據的變量 -> DECLARE id int(11); -> DECLARE origin int(11); -> -- 定義遍歷數據結束標誌 -> DECLARE done BOOLEAN DEFAULT 0; -> -- 定義遊標 -> DECLARE cur CURSOR FOR SELECT -> player.playerid as id, -> player.origin as origin -> FROM player; -> -- 將結束標誌綁定到遊標 -> DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1; -> -- 打開遊標 -> OPEN cur; -> -- 關閉事務自動提交 -> SET autocommit=0; -> -- 開始循環 -> read_loop:LOOP -> -- 提取遊標中的數據 -> FETCH cur INTO id,origin; -> -- 聲明何時結束循環 -> IF done THEN -> LEAVE read_loop; -> END IF; -> -- 循環時的事件 -> IF origin=0 -> THEN -> INSERT INTO consumption VALUES (0,1525467600); -> ELSE -> INSERT INTO consumption_other VALUES(0,1525467600); -> END IF; -> END LOOP; -> commit; -> -- 關閉遊標 -> CLOSE cur; -> END -> // mysql> DELIMITER ; mysql> call add_consumption();
存儲過程相關:
1、創建存儲過程:
格式:
CREATE PROCEDURE 過程名([參數]) 過程體
例子:
mysql> DELIMITER // mysql> CREATE PROCEDURE `originplayer`( -> IN ori int(11), -> OUT total int(11) -> ) -> BEGIN -> select count(*) from player where origin=ori into total; -> END// mysql> DELIMITER ; mysql> call originplayer(0, @total); mysql> select @total; +--------+ | @total | +--------+ | 172 | +--------+
解析:
delimiter是分割符的意思。因爲MySQL默認以“;”爲分割符,如果沒有聲明分割符,那麼編譯器會把存儲過程當作SQL語句進行處理,則存儲過程的編譯過程會報錯。“delimiter //”聲明分割符是“//”。存儲過程中的代碼結束之後,再次聲明“delimiter ;”,將“;”作爲分割符。
創建的存儲過程可能會有輸入、輸出、輸入輸出參數。本例有一個輸入參數“ori”,類型是int,一個輸出參數“total”,類型是int。如果有多個參數,用“,”分割開。
過程體的開始、結束使用BEGIN和END進行標識。
MySQL稱存儲過程的執行爲調用,因此執行存儲過程的語句是CALL。CALL接收存儲過程的名字以及需要傳遞給它的任何參數。
2、參數:
存儲過程共有三種參數類型,INT、OUT、INOUT。形式如:CREATE PROCEDURE([[IN |OUT |INOUT ] 參數名 數據類形...])
IN輸入參數:該參數的值必須在調用存儲過程時指定。如果在存儲過程中修改了該參數的值,該參數的值仍然是修改之前的值。
OUT輸出參數:指定MySQL變量,接收調用存儲過程後返回的值。
INOUT輸入輸出參數:調用時指定,並且可被改變和返回。
3、變量:
定義存儲過程局部變量:
DECLARE variable_name datatype [default value];
datatype與MySQL的數據類型一樣,如:int、float、date、varchar(length);
MySQL變量:MySQL變量一般以@開頭;
變量賦值:
SET variable_name = value
4、查詢存儲過程:
# 列出所有的存儲過程: mysql> show procedure status\G # 列出某個庫擁有的存儲過程: mysql> select name from mysql.proc where db='project'; # 查詢存儲過程的詳細信息: mysql> show create procedure project.originplayer;
5、刪除存儲過程:
mysql> drop procedure project.originplayer;
遊標相關:
1、創建遊標:
mysql> DELIMITER // mysql> CREATE PROCEDURE `getplayerid`() -> BEGIN -> DECLARE id int(11); -> DECLARE done BOOLEAN DEFAULT 0; -> DECLARE cur CURSOR FOR SELECT -> playerid -> FROM player; -> DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1; -> OPEN cur; -> REPEAT -> FETCH cur into id; -> UTIL done END REPEAT; -> CLOSE cur; -> END// mysql> DELIMITER ;
解析:
MySQL遊標僅用於存儲過程中;
DECLARE語句用來定義和命名遊標,這裏的遊標爲“cur”;
OPEN和CLOSE用來打開和關閉遊標。在處理OPEN語句時執行查詢,存儲檢索出的數據以供瀏覽。CLOSE遊標將釋放遊標佔用的所有內存和內部資源。如果沒有明確關閉遊標,MySQL會在到達END語句時自動關閉遊標;
在一個遊標被打開後,使用FETCH語句可以訪問遊標的每一行,並可以指定將數據存儲在什麼地方。
上面例子中,FETCH語句在REPEAT內,因此它反覆執行,直到done爲真(由UTIL done END REPEAT;指定);
CONTINUE HANDLER,當REPEAT由於沒有更多的行供循環而不能繼續時出現這個條件,將done設置爲1,此時REPEAT終止。
2、DECLARE語句的次序:
DECLARE語句的發佈存在特定的次序。用DECLARE語句定義的局部變量必須在定義任意遊標或句柄之前;句柄的定義必須在遊標之後。
3、重複或循環:
除了在1、創建遊標中使用的REPEAT外,MySQL還支持循環語句,用來重複執行代碼,直到使用LEAVE語句手動退出爲止。如下:
…… -> read_loop:LOOP -> -- 提取遊標中的數據 -> FETCH cur INTO id,origin; -> -- 聲明何時結束循環 -> IF done THEN -> LEAVE read_loop; -> END IF; -> -- 循環時的事件 -> IF origin=0 -> THEN -> INSERT INTO consumption VALUES (0,1525467600); -> ELSE -> INSERT INTO consumption_other VALUES(0,1525467600); -> END IF; -> END LOOP; ……