這兩天在做一些簡單的存儲過程,以前並未涉及過,現學現賣,碰到了不少問題,找了很多資料,也差不多解決了,廢話不多說,希望用自己的失敗經驗給猿們提供點幫助。
1. select into 導致游標處理未全部完成
#一般來講,我們會在某個過程(帶有游標或其他循環操作)開始之前定義一個處理完畢的標識
DECLARE done INT DEFAULT 0;
#設置游標信息 (以查詢 a 表 id 為實例)
DECLARE a_id INT DEFAULT 0;
DECLARE b_id INT DEFAULT 0;
DECLARE cur CURSOR FOR (
SELECT ` id` FROM `a_table`;
);
#然而一般我們也會在出現錯誤或者其他情況下重置done的值,如下:
#出現異常(SQLSTATE 02000 | NOT FOUND)
DECLARE CONTINUE HANDLER for SQLSTATE '02000' SET done = 1;
#然后開始游標
OPEN cur;
#獲取第一層游標
FETCH cur INTO a_id;
#開始循環處理(While)
WHILE (done = 0) DO
#查詢關聯信息(這句在某些情況下會出現錯誤,導致游標結束)
SELECT `id` INTO b_id from `b_table` WHERE `a_id` = a_id;
#獲取下一層游標,並繼續循環
FETCH cur INTO o_model_name;
#結束循環處理
END WHILE;
#結束游標
CLOSE cur;
廢話說了這么多,寫了個簡單的例子,簡單的說說會出現問題的原因,正常來說,當b_table中不存在a_id對應的ID值時,將返回null,但由於DECLARE CONTINUE HANDLER for SQLSTATE '02000' SET done = 1;當出現查詢為null的情況時,將會重置done為1,從而不在執行后面的游標,解決方案如下:
SELECT `id` INTO b_id from `b_table` WHERE `a_id` = a_id;
更改為
SET b_id = (SELECT `id` FROM `b_table` WHERE `a_id` = a_id);
后續邏輯可直接判斷b_id的值
IF b_id != '' THEN
#處理邏輯
END IF;
2. function(函數) 與 PROCEDURE(過程)的不同調用方法
function 采用 SELECT 調用,一般會返回返回值,所以最好先定義一個變量用於儲存返回值(如果需要),如帶參數可直接對應賦值參數即可。
DECLARE a_result VARCHAR(100) DEFAULT '';
SELECT function_A([param_1,param_2]) INTO a_result;
procedure 采用 CALL 調用,沒有返回值,主要處理邏輯,可傳參數,特別注意的是:請留意 IN ,OUT ,INOUT三種模式,具體區別百度一下,講的比我清楚。
DECLARE param_1 INT DEFAULT 0;
CALL procedure_A(param_1);
3. 遞歸操作
說實話剛開始使用遞歸是真把我難到了,網上也沒有准確的操作方法,慢慢摸索才理清楚,這里也不出例子了,其實就是結合function(函數) 與 PROCEDURE(過程)就能完美的呈現遞歸操作,這里強調一點,當遞歸操作時,一般會報
ERROR 1456 (HY000): Recursive limit 0 (as set by the max_sp_recursion_depth variable) was exceeded for routine
等錯誤,那是因為默認情況下是不允許使用遞歸操作的,這里需要在需要遞歸操作前生命一個系統變量:
SET @@max_sp_recursion_depth = 100;
后面的數值根據自己的情況設置,表示想要遞歸的層級
總結:新熟悉一個東西都會有很大的難度,但是網上已經有很多前輩給的方法解決,大家一定要多動手多了解,可能我這里有說的錯誤的地方,希望多多理解,有問題就回復,我好更改,哈哈。