前言
我看到在很多教程中,都是把存儲過程和自定義函數一起講,主要是因爲他們兩個非常的相像,而且自定義函數從某種程度上講,更像是存儲過程中的特例。
在這種情況下,我就暫時省略掉自定義函數的筆記,直接繼續瞭解更復雜的存儲過程。
所謂的更復雜,實際上也就是定義變量,變量賦值,遊標以及結構控制語句和循環等,有java語言基礎的情況下,就很好理解了,只是其中有些細節需要稍微注意一下。
定義變量和賦值
之前的例子中,在存儲過程裏只是簡單地做一些基本sql操作,而實際應用中自然遠不止這麼簡單,經常需要聲明變量,並進行一定的操作。
聲明變量的語法是:
DECLARE 變量名 變量類型 約束條件
例如:
DECLARE count INTEGER DEFAULT 100;
給變量賦值的常用語法是:
SET 變量名 = 值;
例如:
SET count = 10;
上邊賦值的語法比較常用,但是還有其他的語法也可以賦值,例如:
SELECT COUNT(*) INTO COUNT FROM USER;
上邊這種根據sql語句的結果進行賦值需要注意的是,當前sql返回值必須是單一的而不能是多個。
結構控制
結構控制我目前瞭解的有兩種,使用if和case,結合上邊變量的知識以及之前存儲過程一起舉例進行說明:
DELIMITER $ CREATE PROCEDURE proce_test0() BEGIN DECLARE COUNT INTEGER DEFAULT 0; DECLARE result VARCHAR(10) DEFAULT ''; SELECT COUNT(*) INTO COUNT FROM USER; IF COUNT
遊標
在上邊的例子中,我們聲明瞭變量,並且把sql語句的結果賦值給了變量,但是這裏的問題就是隻能把單結果的sql賦值給變量。如果要把一個結果集賦值給某個變量進行操作,就需要藉助遊標實現,例如:
DELIMITER $ CREATE PROCEDURE proce_test0() BEGIN DECLARE user_id INTEGER; DECLARE cursor_userId CURSOR FOR SELECT id FROM USER; OPEN cursor_userId; FETCH cursor_userId INTO user_id; SELECT user_id; CLOSE cursor_userId; END $ DELIMITER ;
對上述示例的紅色標記部分解釋如下:
聲明一個user_id變量,類型是INTEGER;
創建一個遊標,名稱是cursor_userId,遊標裏的內容是user表中的id結果集;
打開遊標;
從遊標當前位置取出一條數據,賦值給變量user_id,並把遊標向前移動一位;
輸出變量user_id的值;
關閉遊標。
循環
上述示例中,只是從遊標中取出了一條數據,如果要取出所有數據,比較好的方法就是使用循環遍歷,有while、loop以及repeat,例如:
DELIMITER $ CREATE PROCEDURE proce_test0() BEGIN DECLARE user_id INTEGER; DECLARE flag INTEGER DEFAULT 0; DECLARE idStr NVARCHAR(20) DEFAULT ''; DECLARE cursor_userId CURSOR FOR SELECT id FROM USER; DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = 1; OPEN cursor_userId; WHILE flag != 1 DO FETCH cursor_userId INTO user_id; IF user_id = 5 THEN IF idStr = '' THEN SET idStr = user_id; ELSE SET idStr = CONCAT(idStr,'|',user_id); END IF; END IF; END WHILE; CLOSE cursor_userId; SELECT idStr; END $ DELIMITER ;
上述存儲過程中,我想做的事是這樣的:
把user表中所有id是5的數據用“|”連接成一個字符串。
對上述紅色部分的解釋是:
聲明一個名稱爲user_id的變量,類型是INTEGER;
聲明一個名稱爲flag的變量,類型是INTEGER,默認值是0。這個變量的作用是作爲while循環的條件;
聲明一個名稱是idStr的變量,類型是varchar,長度20,默認值空字符串;
聲明一個遊標,上邊解釋過;
設置遊標讀取到末尾的時候,改變變量flag的值;
打開遊標;
使用while循環,添加條件flag != 1;
從遊標讀取數據,並移動遊標位置,上邊解釋過;
外層if判斷user_id的值,等於5的時候進入內層if;
內層if判斷idStr是否是空字符串,如果是,就把user_id的值賦值給idStr,也就是第一個id前邊不要“|”,否則進行字符串拼接;
結束內層if;
結束外層if;
結束while循環;
關閉遊標;
輸出變量idStr的值。
上邊的存儲過程把while循環替換成loop循環之後如下:
DELIMITER $ CREATE PROCEDURE proce_test0() BEGIN DECLARE user_id INTEGER; DECLARE flag INTEGER DEFAULT 0; DECLARE idStr NVARCHAR(20) DEFAULT ''; DECLARE cursor_userId CURSOR FOR SELECT id FROM USER; DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = 1; OPEN cursor_userId; loop_test:LOOP IF flag =1 THEN LEAVE loop_test; END IF; FETCH cursor_userId INTO user_id; IF user_id = 5 THEN IF idStr = '' THEN SET idStr = user_id; ELSE SET idStr = CONCAT(idStr,'|',user_id); END IF; END IF; END LOOP; CLOSE cursor_userId; SELECT idStr; END $ DELIMITER ;
重點在紅色部分,其中loop_test是自定義的名字,可以理解成java中for循環前的標籤。然後需要if判斷一個臨界條件來終止循環,終止的語法就是leave 循環名
,相當於java的for循環裏的break。最後的end loop結束循環。
同樣的,上邊的寫法也可以用repeat循環來代替:
DELIMITER $ CREATE PROCEDURE proce_test0() BEGIN DECLARE idStr VARCHAR(20) DEFAULT ''; DECLARE user_id INTEGER; DECLARE flag INTEGER DEFAULT 0; DECLARE cursor_id CURSOR FOR SELECT id FROM USER; DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = 1; OPEN cursor_id; REPEAT FETCH cursor_id INTO user_id; IF user_id =5 THEN IF idStr = '' THEN SET idStr = user_id; ELSE SET idStr = CONCAT(idStr,"|",user_id); END IF; END IF; UNTIL flag =1 END REPEAT; CLOSE cursor_id; SELECT idStr; END $ DELIMITER ;
repeat循環的終止,需要藉助於until關鍵字,這種語法結構的寫法其實很像是java中的do while循環,先給一個關鍵詞,然後是循環體,最後寫終止循環的條件。
通過上邊的示例,就可以基本瞭解變量聲明和賦值,結構控制語句,遊標,循環等語法的用法,從而組合起來生成相對複雜的存儲過程了。