MySql存儲過程與函數詳解(引用)

存儲過程和函數是在數據庫中定義一些SQL語句的集合,而後直接調用這些存儲過程和函數來執行已經定義好的SQL語句。存儲過程和函數能夠避免開發人員重複的編寫相同的SQL語句。並且,存儲過程和函數是在MySQL服務器中存儲和執行的,能夠減小客戶端和服務器端的數據傳輸。
1、存儲過程
1.一、基本語法sql

CREATE PROCEDURE sp_name ([proc_parameter[,...]])  
  
  [characteristic ...] routine_body  數據庫

Sp_name:存儲過程的名稱,默認在當前數據庫中建立。這個名稱應當儘可能避免與MySQL的內置函數相同的名稱編程

 Proc_parameter:存儲過程的參數列表
      格式[IN|OUT|INOUT]param_name type
      Param_name爲參數名,type爲參數的數據類型。多個參數彼此間用逗號分隔。輸入參數、輸出參數和輸入/輸出參數,分別用in/out/inout標識。參數的取名不要與數    據表的列名相同。
Characteristic:存儲過程的某些特徵設定,分別介紹
        1 COMMENT'string':用於對存儲過程的描述,其中string爲描述內容,comment爲關鍵字。
        2 LANGUAGE SQL:指明編寫這個存儲過程的語言爲SQL語言。這個選項能夠不指定。
        3 DETERMINISTIC:表示存儲過程對一樣的輸入參數產生相同的結果;NOT DETERMINISTIC,則表示會產生不肯定的結果(默認)。
        4 contains sql | no sql | reads sql data | modifies sql data Contains sql表示存儲過程包含讀或寫數據的語句(默認)
        No sql表示不包含sql語句
        Reads sql data表示存儲過程只包含讀數據的語句
        Modifies sql data 表示存儲過程只包含寫數據的語句
        5 sql security:這個特徵用來指定存儲過程使用建立該存儲過程的用戶(definer)的許可來執行,仍是使用調用者(invoker)的許可來執行。默認是definer
    Routine_body:存儲過程的主體部分,包含了在過程調用的時候必須執行的sql語句。以begin開始,以end結束。若是存儲過程體中只有一條sql語句,能夠省略begin-end標誌。
1.二、數據準備
服務器

?
1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE
  t_user
  (
   USER_ID INT NOT NULL AUTO_INCREMENT,
   USER_NAME CHAR (30) NOT NULL ,
   USER_PASSWORD CHAR (10) NOT NULL ,
   USER_EMAIL CHAR (30) NOT NULL ,
   PRIMARY KEY (USER_ID),
   INDEX IDX_NAME (USER_NAME)
  )
  ENGINE=InnoDB DEFAULT CHARSET=utf8;

而後這是插入的一些數據:函數

1.3 IN、OUT、INOUT參數
(1)、帶IN的存儲過程oop

?
1
2
3
4
5
6
7
8
9
//建立儲存過程.cmd 中運行
CREATE PROCEDURE SP_SEARCH( IN p_name CHAR (20))
BEGIN
IF p_name is null or p_name= '' THEN
SELECT * FROM t_user;
ELSE
SELECT * FROM t_user WHERE USER_NAME LIKE p_name;
END IF;
END

由於;分會衝突,因此要加delimiter //。將//設置爲結束運行符號fetch

以下:spa

調用:.net

?
1
2
//調用並輸出結果
CALL SP_SEARCH( '林炳文' )

結果code

(2)、帶OUT的存儲過程

?
1
2
3
4
5
6
7
8
9
10
//帶 OUT 返回的
CREATE PROCEDURE SP_SEARCH2( IN p_name CHAR (20), OUT p_int INT )
BEGIN
IF p_name is null or p_name= '' THEN
SELECT * FROM t_user;
ELSE
SELECT * FROM t_user WHERE USER_NAME LIKE p_name;
END IF;
SELECT FOUND_ROWS() INTO p_int;
END

調用輸出:統計帶林開頭的人數

?
1
2
3
//調用並輸出結果
CALL SP_SEARCH2( '林%' ,@p_num);
SELECT @p_num;

(3)、帶INOUT的存儲過程

?
1
2
3
4
5
6
7
8
9
//帶INOUT的存儲過程
CREATE PROCEDURE sp_inout(INOUT p_num INT )
BEGIN
SET p_num=p_num*10;
END
//調用並輸出結果
SET @p_num=2;
call sp_inout(@p_num);
SELECT @p_num;

輸出結果:

1.四、存儲過程體    
       存儲過程體中可使用各類sql語句和過程式語句的組合,來封裝數據庫應用中複雜的業務邏輯和處理規則,以實現數據庫應用的靈活編程。下面主要介紹幾個用於構造存儲過程體的經常使用語法元素。
一、局部變量
在存儲過程體中能夠聲明局部變量,用來存儲存儲過程體中臨時結果。

?
1
2
3
4
DECLARE var_name[,…] type [ DEFAULT value]
Var_name:指定局部變量的名稱
Type:用於聲明局部變量的數據類型
default 子句:用於爲局部變量指定一個默認值。若沒有指定,默認爲 null .

如:

?
1
Declare cid int (10);

使用說明:
局部變量只能在存儲過程體的begin…end語句塊中聲明。
局部變量必須在存儲過程體的開頭處聲明。
局部變量的做用範圍僅限於聲明它的begin..end語句塊,其餘語句塊中的語句不可使用它。
局部變量不一樣於用戶變量,二者區別:局部變量聲明時,在其前面沒有使用@符號,而且它只能在begin..end語句塊中使用;而用戶變量在聲明時,會在其名稱前面使用@符號,同時已聲明的用戶變量存在於整個會話之中。
二、set語句
使用set語句爲局部變量賦值

Set var_name=expr  
Set cid=910;  

三、select … into 語句
把選定列的值直接存儲到局部變量中,語法格式

?
1
2
3
4
Select col_name[,…] into var_name[,…] table_expr
Col_name:用於指定列名
Var_name:用於指定要賦值的變量名
Table_expr:表示 select 語句中的 from 字句及後面的語法部分

說明:存儲過程體中的select…into語句返回的結果集只能有一行數據。
四、定義處理程序
是事先定義程序執行過程當中可能遇到的問題。而且能夠在處理程序中定義解決這些問題的辦法。這種方式能夠提早預測可能出現的問題,並提出解決方法。

?
1
2
3
DECLARE handler_type HANDLER FOR condition_value[,…] sp_statement
handler_type: CONTINUE | EXIT | UNDO
Condition_value:Sqlwarning | not found | sqlexception

五、流程控制語句
(1)條件判斷語句
If語句

?
1
2
3
4
If search_condition then statement_list
[elseif search_condition then statement_list]…
[ else statement_list]
End if

Search_condition參數:條件判斷語句
Statement_list參數:不一樣條件的執行語句
多重IF的存儲過程實例
數據準備

學生表:

 

?
1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE
  t_student
  (
   STU_ID INT NOT NULL ,
   STU_NAME CHAR (10) NOT NULL ,
   STU_CLASS INT NOT NULL ,
   STU_SEX CHAR (2) NOT NULL ,
   STU_AGE INT NOT NULL ,
   PRIMARY KEY (STU_ID)
  )
  ENGINE=InnoDB DEFAULT CHARSET=utf8;

數據以下:

成績表(STU_ID是學生表是外鍵關係):

?
1
2
3
4
5
6
7
8
9
CREATE TABLE
  t_grade
  (
   STU_ID INT NOT NULL ,
   STU_SCORE INT NOT NULL ,
   FOREIGN KEY (STU_ID) REFERENCES t_student (STU_ID),
   INDEX STU_ID (STU_ID)
  )
  ENGINE=InnoDB DEFAULT CHARSET=utf8;

而後寫一個存儲過程:返回各個分數等級的人

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//帶多重IF的存儲過程
CREATE PROCEDURE SP_SCHOLARSHIP_LEVEL( IN p_level char (1))
BEGIN
IF p_level = 'A' THEN
SELECT * FROM t_grade WHERE STU_SCORE >=90;
ELSEIF p_level = 'B' THEN
SELECT * FROM t_grade WHERE STU_SCORE <90 AND STU_SCORE>=80;
ELSEIF p_level = 'C' THEN
SELECT * FROM t_grade WHERE STU_SCORE <80 AND STU_SCORE>=70;
ELSEIF p_level = 'D' THEN
SELECT * FROM t_grade WHERE STU_SCORE <60;
ELSE
SELECT * FROM t_grade;
END IF;
END

調用過程:

?
1
2
//調用並輸出結果
CALL SP_SCHOLARSHIP_LEVEL( 'A' );

Case 語句
表達形式1

?
1
2
3
4
5
Case case_value
When when_value then statement_list
[ When when_value then statement_list]…
[ else statement_list]
End case

表達形式2

?
1
2
3
Case
When search_condition then statement_list
End case

使用範例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CREATE PROCEDURE SP_SCHOLARSHIP_LEVEL3( IN p_level char (1))
BEGIN
DECLARE p_num int DEFAULT 0;
CASE p_level
WHEN 'A' THEN
SET p_num=90;
WHEN 'B' THEN
SET p_num=80;
WHEN 'C' THEN
SET p_num=70;
WHEN 'D' THEN
SET p_num=60;
ELSE
SET p_num=0;
END CASE ;
SELECT * FROM t_grade g, t_student s WHERE g.STU_ID=s.STU_ID AND g.STU_SCORE >= p_num ;
END

調用:

?
1
2
//調用並輸出結果
CALL SP_SCHOLARSHIP_LEVEL3( 'd' );

(2)循環語句
While語句、repeat語句和loop語句。
While語句

?
1
2
3
4
5
[begin_label:]
while search_condition do
Statement_list
End while
[end_label]

 判斷條件search_condition是否爲真,若爲真,則執行statement_list中的語句,而後再進行判斷,如若仍然爲真則繼續循環,直至條件判斷不爲真時循環結束。
使用範例

?
1
2
3
4
5
6
7
8
9
10
11
12
//帶while的存儲過程
CREATE PROCEDURE sp_cal( IN p_num INT , OUT p_result INT )
BEGIN
  SET p_result=1;
  WHILE p_num > 1 DO
  SET p_result = p_num * p_result;
  SET p_num = p_num-1;
  END WHILE;
END
//調用並輸出結果
CALL sp_cal(5,@result);
SELECT @result;

輸出結果:計算5!

Repeat語句語法格式

?
1
2
3
4
5
6
[begin_label:]
repeat
Statement_list
Until search_condition
End repeat
[end_label]  

Repeat語句首先執行statement_list中的語句,而後判斷條件search_condition是否爲真,假若爲真,則結束循環,若不爲真,繼續循環。
Repeat先執行後判斷,while先判斷後執行。
使用範例:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
//帶repeat的存儲過程
CREATE PROCEDURE sp_cal2( IN p_num INT , OUT p_result INT )
BEGIN
  SET p_result=1;
  REPEAT
   SET p_result = p_num * p_result;
   SET p_num = p_num-1;
   UNTIL p_num<=1
  END REPEAT;
END
//調用並輸出結果
CALL sp_cal2(5,@result);
SELECT @result;

1.五、 調用存儲過程

?
1
2
3
Call sp_name([parameter[,…]]);
Sp_name被調用存儲過程的名稱
Parameter:指定調用存儲過程所要使用的參數。

 1.六、 修改存儲過程

 

複製代碼代碼以下:
Alter procedure proc_name[characteristic…] 

 

只能修改存儲過程的特徵,若是要修改存儲過程的內容,能夠先刪除該存儲過程,而後再從新建立
1.七、 刪除存儲過程

 

複製代碼代碼以下:
Drop procedure [if exists] sp_name; 

 

2、函數
2.一、 定義

?
1
2
3
4
5
MySQL中,建立存儲函數的基本形式以下:
CREATE FUNCTION sp_name([func_parameter[,...]])
RETURNS type
[characteristic ...] routine_body
Return

子句用於聲明存儲函數返回值的數據類型。存儲過程是用戶定義的一系列sql語句的集合,涉及特定表或其它對象的任務,用戶能夠調用存儲過程,而函數一般是數據庫已定義的方法,它接收參數並返回某種類型的值而且不涉及特定用戶表。
調用存儲函數

?
1
2
Select sp_name([func_parameter…])
Select fn_search(2);

刪除存儲函數drop
修改存儲函數alter 修改存儲函數的某些相關特徵。

2.二、函數使用例子
(比較大小 ,返回大的數)

?
1
2
3
4
5
6
7
8
9
10
/**函數使用**/
CREATE FUNCTION sp_cal_max(p_num1 INT ,p_num2 INT )
RETURNS INT
BEGIN
IF p_num1 >= p_num2 THEN
RETURN p_num1;
ELSE
RETURN p_num2;
END IF;
END

調用:

?
1
2
3
SET @p_num1=2;
SET @p_num2=34;
SELECT sp_cal_max(@p_num1,@p_num2);

2.三、存儲過程和函數區別
1)通常來講,存儲過程實現的功能要複雜一點,而函數的實現的功能針對性比較強。存儲過程,功能強大,能夠執行包括修改表等一系列數據庫操做;用戶定義函數不能用於執行一組修改全局數據庫狀態的操做。

2)對於存儲過程來講能夠返回參數,如記錄集,而函數只能返回值或者表對象。函數只能返回一個變量;而存儲過程能夠返回多個。存儲過程的參數能夠有IN,OUT,INOUT三種類型,而函數只能有IN類~~存儲過程聲明時不須要返回類型,而函數聲明時須要描述返回類型,且函數體中必須包含一個有效的RETURN語句。

3)存儲過程,可使用非肯定函數,不容許在用戶定義函數主體中內置非肯定函數。

4)存儲過程通常是做爲一個獨立的部分來執行( EXECUTE 語句執行),而函數能夠做爲查詢語句的一個部分來調用(SELECT調用),因爲函數能夠返回一個表對象,所以它能夠在查詢語句中位於FROM關鍵字的後面。 SQL語句中不可用存儲過程,而可使用函數。
3、光標(遊標)
 3.1 定義
     查詢語句可能查詢出多條記錄,在存儲過程和函數中使用光標標來逐條讀取查詢結果集中的記錄。光標的使用包括聲明光標、打開光標、使用光標和關閉光標。光標必須聲明光標、打開光標、使用光標和關閉光標。光標必須聲明在處理程序以前,而且聲明在變量和條件以後。
1 聲明光標

?
1
2
3
4
Declare cursor_name cursor forselect_statement;
Cursor_name:光標名稱
Select_statement: select 語句的內容
Declare cur_employee cursor forselect name ,age from employee;

2 打開光標

?
1
2
Open cursor_name
Open cur_employee;

3 使用光標
Mysql中使用fetch關鍵字來使用光標,語法形式

?
1
2
3
4
Fetch cur_name intovar_name[,var_name…];
Cur_name表示光標的名稱
Var_name表示將光標中的 select 語句查詢出來的信息存入該參數。Var_name必須在聲明光標前就定義好。
Fetch cur_employee intoemp_name,emp_age;

4 關閉光標

?
1
2
Close cursor_name;
Close cur_employee;

每一個光標再也不須要時都應該被關閉,使用close語句將會釋放光標所使用的所有資源。在一個光標被關閉後,若是沒有從新被打開,則不能被使用。對於聲明過的光標,則不須要再次聲明,可直接使用open語句打開。
3.二、使用範例
(將表test_cur1數據複製到test_cur2)

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CREATE TABLE `test_cur1` (
  `id` int (11) NOT NULL auto_increment,
  `type` char (11) default NULL ,
  `order1` char (11) default NULL ,
  PRIMARY KEY (`id`)
)
INSERT INTO `test_cur1` VALUES (1, '145' , 'd1' );
INSERT INTO `test_cur1` VALUES (2, '134' , '1d' );
INSERT INTO `test_cur1` VALUES (3, '123' , '1ad' );
INSERT INTO `test_cur1` VALUES (4, '121' , '1as' );
  
CREATE TABLE `test_cur2` (
  `id` int (11) NOT NULL auto_increment,
  `type` char (11) default NULL ,
  `order1` char (11) default NULL ,
  PRIMARY KEY (`id`)
)

而後寫光標了:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
create procedure get_cur ()
BEGIN
  DECLARE done INT DEFAULT 0;
  DECLARE ID int (11);
  DECLARE type char (11);
  DECLARE order1 char (11);
  DECLARE mycur CURSOR FOR SELECT * FROM test_cur1;//定義光標
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
  //打開光標
  OPEN mycur;
  //開始循環
  REPEAT
  FETCH mycur INTO ID,type,order1;//取出光標的內容到臨時變量
  IF NOT done THEN
   INSERT INTO test_cur2 VALUES (ID,type,order1);//插入到另外一張表
  END IF;
  UNTIL done END REPEAT;//當done=1時結束循環
  //關閉光標
  CLOSE mycur;
END

運行:

?
1
call get_cur()

來看看兩張表的數據:這是表2

這是表1

說明數據已成功複製過去了。

相關文章
相關標籤/搜索