存儲過程和函數是在數據庫中定義一些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.六、 修改存儲過程
只能修改存儲過程的特徵,若是要修改存儲過程的內容,能夠先刪除該存儲過程,而後再從新建立
1.七、 刪除存儲過程
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
說明數據已成功複製過去了。