mysql之procedure() and function()

自行創(chuàng)建一個(gè)員工信息表info,里面記錄著員工姓名,年齡,地址以及工資,下面的實(shí)驗(yàn)要使用。

mysql> create database testdb charset utf8;

mysql> use testdb;

mysql> create table info(ID int not null auto_increment primary key,NAME CHAR(8) NOT NULL,

?????? AGE INT NOT NULL,

?????? ADDRESS VARCHAR(20) NOT NULL,

?????? SALARY decimal(10,2) not null) ENGINE=innodb;

mysql> INSERT INTO info(NAME,AGE,ADDRESS,SALARY) VALUES('ZHANG',32,'Beijing',2000.00);

mysql> INSERT INTO info(NAME,AGE,ADDRESS,SALARY) VALUES('LI',25,'Shanghai',1500.00);

mysql> INSERT INTO info(NAME,AGE,ADDRESS,SALARY) VALUES('PENG',23,'Hangzhou',2000.00);

mysql> INSERT INTO info(NAME,AGE,ADDRESS,SALARY) VALUES('LIN',25,'Henan',6500.00);

mysql> INSERT INTO info(NAME,AGE,ADDRESS,SALARY) VALUES('WANG',27,'Hunan',8500.00);

mysql> INSERT INTO info(NAME,AGE,ADDRESS,SALARY) VALUES('WANG',22,'Hunan',4500.00);

mysql> INSERT INTO info(NAME,AGE,ADDRESS,SALARY) VALUES('GAO',24,'Hebei',10000.00);

存儲(chǔ)過程和存儲(chǔ)函數(shù)

簡單地說,存儲(chǔ)過程就是一條或者多條SQL語句的集合,可視為批文件,但是其作用不僅限于批處理。

存儲(chǔ)程序可以分為存儲(chǔ)過程和函數(shù),MySQL中創(chuàng)建存儲(chǔ)過程和函數(shù)使用的語句分別是CREATE PROCEDURE和CREATE FUNCTION。使用CALL語句來調(diào)用存儲(chǔ)過程,只能用輸出變量返回值,函數(shù)可以從語句外調(diào)用(即通過引用函數(shù)名),也能返回標(biāo)量值。存儲(chǔ)過程也可以調(diào)用其他存儲(chǔ)過程。

存儲(chǔ)過程的好處:

1.由于數(shù)據(jù)庫執(zhí)行動(dòng)作時(shí),是先編譯后執(zhí)行的,然而存儲(chǔ)過程是一個(gè)編譯過的代碼塊,所以執(zhí)行效率要比T-SQL語句高。

2.一個(gè)存儲(chǔ)過程在程序在網(wǎng)絡(luò)中交互時(shí)可以替代大堆的T-SQL語句,所以也能降低網(wǎng)絡(luò)的通信量,提高通信速率。

3.通過存儲(chǔ)過程能夠使沒有權(quán)限的用戶在控制之下間接地存取數(shù)據(jù)庫,從而確保數(shù)據(jù)的安全。

4.可在生產(chǎn)環(huán)境下執(zhí)行,修復(fù)BUG。

創(chuàng)建存儲(chǔ)過程

創(chuàng)建存儲(chǔ)過程,需要使用CREATE PROCEDURE語句,基本語法格式如下:

CREATE [DEFINER = { user | CURRENT_USER }] PROCEDURE sp_name ([proc_parameter[,...]]) [characteristic ...] routine_body

CREATE PROCEDURE為用來創(chuàng)建存儲(chǔ)函數(shù)的關(guān)鍵字;sp_name為存儲(chǔ)過程的名稱;proc_parameter為指定存儲(chǔ)過程的參數(shù)列表,可省略,列表形式如下:

[ IN | OUT | INOUT ] param_name type

其中,IN表示輸入?yún)?shù),OUT表示輸出參數(shù),INOUT表示既可以輸入也可以輸出;param_name表示參數(shù)名稱;type表示參數(shù)的類型,該類型可以是MySQL數(shù)據(jù)庫中的任意類型。另外如果你傳入的參數(shù)中文的,那么還可以在“[ IN | OUT | INOUT ] param_name type”加入字符集,如“IN id INT character set utf8”。

Characteristics指定存儲(chǔ)過程的特性,有以下取值:

LANGUAGE SQL

說明routine_body部分是由SQL語句組成的,當(dāng)前系統(tǒng)支持的語言為SQL,SQL是LANGUAGE特性的唯一值。

[NOT] DETERMINISTIC

指明存儲(chǔ)過程執(zhí)行的結(jié)果是否正確,DETERMINISTIC表示結(jié)果是確定的。每次執(zhí)行存儲(chǔ)過程時(shí),相同的輸入會(huì)得到相同的輸出。NOT DETERMINISTIC表示結(jié)果是不確定的,相同的輸入可能得到不同的輸出。如果沒有指定任意一個(gè)值,默認(rèn)為NOT DETERMINISTIC。

{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }

指明子程序使用SQL語句的限制。CONTAINS SQL表明子程序包含SQL語句,但是不包含讀寫數(shù)據(jù)的語句;NO SQL表明子程序不包含SQL語句;READS SQL DATA說明子程序包含讀數(shù)據(jù)的語句;MODIFIES SQL DATA表明子程序包含寫數(shù)據(jù)的語句。默認(rèn)情況下,系統(tǒng)會(huì)指定為CONTAINS SQL。

SQL SECURITY { DEFINER | INVOKER}

指明誰有權(quán)限來執(zhí)行,DEFINER表示只有定義者才能執(zhí)行。INVOKER表示擁有權(quán)限的調(diào)用者可以執(zhí)行。默認(rèn)情況下,系統(tǒng)指定為DEFINER。

COMMENT ‘string’

注釋信息,可以用來描述存儲(chǔ)過程或函數(shù)。

routine_body

是SQL代碼的內(nèi)容,可以用BEGIN…END來表示SQL代碼的開始和結(jié)束。

編寫存儲(chǔ)過程并不是件簡單的事情,可能存儲(chǔ)過程中需要復(fù)雜的SQL語句,并且要有創(chuàng)建存儲(chǔ)過程的權(quán)限;但是使用存儲(chǔ)過程將簡化操作,減少冗余的操作步驟,同時(shí),還可以減少操作過程中的失誤,提高效率,因此存儲(chǔ)過程時(shí)非常有用的。

下面是一個(gè)簡單存儲(chǔ)過程的實(shí)例:

mysql> use testdb;

mysql> delimiter $

mysql> create procedure test()

?????? begin

?????? select * from testdb.info;

?????? end $

mysql> delimiter ;

其中,“delimiter $”語句的作用是將MySQL的結(jié)束符設(shè)置為“$”符,因?yàn)镸ySQL默認(rèn)的語句結(jié)束符為分號“;”,為了避免與存儲(chǔ)過程中SQL語句結(jié)束符相沖突,所以就是用delimiter改變存儲(chǔ)過程的結(jié)束符,并以“END $”結(jié)束存儲(chǔ)過程,其中存儲(chǔ)過程定義完畢之后再使用“delimiter ;”恢復(fù)默認(rèn)結(jié)束符。

然后開始定義存儲(chǔ)過程,此存儲(chǔ)過程名為test,使用CREATE PROCEDURE test()語句定義。此存儲(chǔ)過程沒有參數(shù),但是后面的()仍然需要。BEGIN和END語句用來限定存儲(chǔ)過程體,過程本身僅是一個(gè)簡單的SELECT語句。每次調(diào)用這個(gè)存儲(chǔ)過程的時(shí)候都會(huì)執(zhí)行SELECT語句查看表。當(dāng)然存儲(chǔ)過程也可以是很多語句的復(fù)雜的組合,就好像這個(gè)例子剛開始給出的那個(gè)語句一樣,其本身也可以調(diào)用其他的函數(shù),來組成更加復(fù)雜的操作。

操作存儲(chǔ)過程

1)查看存儲(chǔ)過程

mysql> SHOW PROCEDURE STATUS\G

*************************** 1. row ***************************

Db: testdb

Name: test

Type: PROCEDURE

Definer: root@localhost

Modified: 2016-12-22 15:09:15

Created: 2016-12-22 15:09:15

Security_type: DEFINER

Comment:

character_set_client: utf8

collation_connection: utf8_general_ci

Database Collation: utf8_general_ci

1 row in set (0.00 sec)

存儲(chǔ)過程的默認(rèn)安全類型是DEFINER,并且Definer的用戶為創(chuàng)建這個(gè)存儲(chǔ)過程的用戶。

另外在mysql.proc中也有存儲(chǔ)過程的信息。

mysql> select * from mysql.proc\G

2)查看存儲(chǔ)過程創(chuàng)建過程

mysql> show create procedure test\G

*************************** 1. row ***************************

?????????? Procedure: test

????????????sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION

????Create Procedure: CREATE DEFINER=`root`@`localhost` PROCEDURE `test`()

begin

select * from testdb.info;

end

??character_set_client: utf8

??collation_connection: utf8_general_ci

??Database Collation: utf8_general_ci

1 row in set (0.00 sec)

3)調(diào)用存儲(chǔ)過程

mysql> CALL test();

4)刪除存儲(chǔ)過程

mysql> DROP PROCEDURE procedure_name;

5)修改存儲(chǔ)過程權(quán)限

方法一:修改存儲(chǔ)過程的definer

mysql> update mysql.proc set definer='root'@'192.168.2.%' where db='db_name';

方法二:修改sql security

sql secuirty的值決定了調(diào)用存儲(chǔ)過程的方式,取值definer或者invoker(默認(rèn)是definer)。

definer:在執(zhí)行存儲(chǔ)過程前驗(yàn)證definer對應(yīng)的用戶,如:’root’@’192.168.2.%’是否存在,以及是否具有執(zhí)行存儲(chǔ)過程的權(quán)限,若沒有則報(bào)錯(cuò)。簡單來說就是執(zhí)行這個(gè)存儲(chǔ)過程的用戶不管是誰也不管有沒有權(quán)限執(zhí)行,只要’root’@’192.168.2.%’這個(gè)用戶存在且有執(zhí)行的權(quán)限即可。

invoker:在執(zhí)行存儲(chǔ)過程時(shí)判斷inovker,即調(diào)用該存儲(chǔ)過程的用戶是否有相應(yīng)權(quán)限,若沒有則報(bào)錯(cuò)。簡單來說也就是根據(jù)執(zhí)行用戶本身權(quán)限為主。

修改語法:

mysql> alter procedure procedure_name sql security invoker;

也可以在創(chuàng)建存儲(chǔ)過程的時(shí)候給定definer=’test’@’%’,如下:

mysql> use testdb;

mysql> delimiter $

mysql> create definer='test'@'%' procedure test1()

?????? begin

?????? select * from testdb.info;

?????? end $

mysql> delimiter ;

這個(gè)時(shí)候由于是definer模式,所以如果你的’test’@’%’用戶沒有執(zhí)行這個(gè)存儲(chǔ)過程的權(quán)限或者此用戶不存在的話,其他用戶執(zhí)行這個(gè)存儲(chǔ)過程就會(huì)報(bào)錯(cuò)。信息如下:

ERROR 1370 (42000): execute command denied to user 'tt'@'%' for routine 'testdb.test1'

下面再創(chuàng)建一個(gè)可以傳參的存儲(chǔ)過程。

mysql> use testdb;

mysql> delimiter $

mysql> create procedure param(n int)

????begin

????select * from testdb.info where salary > n;

?????? end $

mysql> delimiter ;

mysql> call param(5000);

創(chuàng)建一個(gè)param存儲(chǔ)過程,定義一個(gè)參數(shù)n,類型為int;然后執(zhí)行SQL語句的時(shí)候使用參數(shù)n作為條件,最后調(diào)用存儲(chǔ)過程時(shí)輸入?yún)?shù)值。

創(chuàng)建存儲(chǔ)函數(shù)

創(chuàng)建存儲(chǔ)函數(shù),需要使用CREATE FUNCITON語句,基本語法格式如下:

CREATE FUNCTION fun_name ([fun_parameer])

RETURENS type

[characteristic …] routine_body

CREATE FUNCTION為用來創(chuàng)建存儲(chǔ)函數(shù)的關(guān)鍵字;fun_name表示存儲(chǔ)函數(shù)的名稱;fun_parameter為存儲(chǔ)過程的參數(shù)列表,參數(shù)列表形式如下:

[ IN | OUT | INOUT ] param_name type

其中,IN表示輸入?yún)?shù),OUT表示輸出參數(shù),INOUT表示既可以輸入也可以輸出;param_name表示參數(shù)名稱;type表示參數(shù)的類型,該類型可以是MySQL數(shù)據(jù)庫中的任意類型。

RETURNS type語句表示函數(shù)返回?cái)?shù)據(jù)的類型;characteristic:指定存儲(chǔ)函數(shù)的特性,取值與創(chuàng)建存儲(chǔ)過程時(shí)相同,詳細(xì)的看存儲(chǔ)過程就行了。

下面創(chuàng)建一個(gè)存儲(chǔ)函數(shù),名稱為fun,參數(shù)定義為空,該函數(shù)返回SELECT語句的查詢結(jié)果,數(shù)值為字符串型,代碼如下:

mysql> DELIMITER $

mysql> CREATE FUNCTION fun() RETURNS char(200)

????BEGIN

????RETURN (SELECT SALARY from testdb.info WHERE NAME="ZHANG");

?????? end$

mysql> DELIMITER ;

如果在存儲(chǔ)函數(shù)中的RETURN語句返回一個(gè)類型不同于函數(shù)的RETURNS字句中指定類型的值,返回值將被強(qiáng)制為恰當(dāng)?shù)念愋汀1热纾绻粋€(gè)函數(shù)返回一個(gè)ENUM或SET值,但是RETURN語句返回一個(gè)整數(shù),對于SET成員集的相應(yīng)的ENUM成員,從函數(shù)返回的值時(shí)字符串。

MySQL存儲(chǔ)過程和函數(shù)有什么區(qū)別?在本質(zhì)上他們都是存儲(chǔ)程序,函數(shù)只能通過return語句返回單個(gè)值或者表對象;而存儲(chǔ)過程不允許執(zhí)行return,但是可以通過out參數(shù)返回多個(gè)值。函數(shù)限制比較多,不能用臨時(shí)表,只能用表變量,還有一個(gè)些函數(shù)都不可用等等;而存儲(chǔ)過程的限制相對就比較少。函數(shù)可以嵌入在SQL語句中使用,可以在SELECT語句中作為查詢語句的一個(gè)部分帶哦用;而存儲(chǔ)過程一般是作為一個(gè)獨(dú)立的部分來執(zhí)行。

變量的使用

在編寫存儲(chǔ)過程中,可以定義變量,變量可以在子程序中聲明并使用,這些變量的作用范圍是在BEGIN…END程序中。

1)定義變量

在存儲(chǔ)過程中使用DECLARE語句定義變量,語法格式如下:DECLARE var_name date_type [DEFAULT value];

var_name為局部變量的名稱,DEFAULT value子句給變量提供一個(gè)默認(rèn)值。值除了可以被聲明為一個(gè)常數(shù)之外,還可以被指定為一個(gè)表達(dá)式。如果沒有DEFAULT子句,初始值為NULL。

實(shí)例:定義名稱為myparam的變量,類型為INT類型,默認(rèn)值為100,代碼如下。

mysql> delimiter $

mysql> create procedure var1()

begin

??DECLARE myparam INT DEFAULT 100;

end$

2)輸出變量

在MySQL中輸出變量的方式為select @@log_bin;,但在存儲(chǔ)過程中輸出變量的方式為SELECT var_name;即可,具體代碼如下:

mysql> create procedure var2()

begin

??DECLARE myparam INT DEFAULT 100;

??SELECT myparam;

end$

mysql> call p2()\G

*************************** 1. row ***************************

var: 100

3)為變量賦值

定義變量之后,為變量賦值可以改變變量的默認(rèn)值,MySQL中使用SET語句為變量賦值,語法格式如下:

SET var_name=expr[,var_name=expr]…;

在存儲(chǔ)程序中的SET語句時(shí)一般SET語句的擴(kuò)展版本,被參考變量可能是子程序內(nèi)聲明的變量,或者是全局服務(wù)器變量,如系統(tǒng)變量或者用戶變量。

在存儲(chǔ)程序中的SET語句作為預(yù)先存在的SET語法的一部分來實(shí)現(xiàn),這允許SET a=x,b=y,…這樣的擴(kuò)展語法。其中不同的變量類型(局域聲明變量即全局變量)可以被混合起來。這也允許把局部變量和一些只對系統(tǒng)變量有意義的選項(xiàng)合并起來。下面聲明三個(gè)變量,然后使用SET為變量賦值。代碼如下:

mysql> create procedure var3()

begin

??DECLARE var1,var2,var3 INT;

??SET var1 = 10, var2 = 20;

??SET var3 = var1+var2;

??SELECT var3;

end$

mysql> call var3()\G

*************************** 1. row ***************************

Var3: 30

MySQL中可以通過SELECT … INTO為一個(gè)或多個(gè)變量賦值,語法如下:

SELECT col INTO var_name FROM table_name

代碼如下:

mysql> create procedure var4()

begin

??DECLARE var INT;

??select count(*) into var from testdb.info;

??SELECT var;

end$

mysql> delimiter ;

mysql> call var4()\G

*************************** 1. row ***************************

var: 7

定義條件和處理程序

特定條件需要特定處理,這些條件可以聯(lián)系到錯(cuò)誤,以及子程序中的一般流程控制。定義條件是事先定義程序執(zhí)行過程中遇到的問題,處理程序定義了在遇到這些問題時(shí)應(yīng)當(dāng)采取的處理方式,并且保證存儲(chǔ)過程或函數(shù)在遇到警告或錯(cuò)誤時(shí)能繼續(xù)執(zhí)行。這樣可以增強(qiáng)存儲(chǔ)程序處理問題的能力,避免程序異常停止運(yùn)行。如果需要可以通過DECLARE關(guān)鍵字來定義條件和處理程序。


流程控制的使用

在存儲(chǔ)過程中可以定義流程控制語句,流程控制語句用來根據(jù)條件控制語句的執(zhí)行,MySQL中的用來構(gòu)造控制流程的語句有:IF語句、CASE語句、LOOP語句、WHILE語句、LEAVE語句、ITERATE語句和REPEAT語句。每個(gè)流程中可能包含一個(gè)單獨(dú)語句,或者是使用BEGIN…END構(gòu)造的復(fù)合語句,構(gòu)造可以被嵌套。下面介紹這些流程控制語句

1)IF語句

IF語句包含多個(gè)條件判斷,根據(jù)判斷的結(jié)果為TRUE或FALSE執(zhí)行相應(yīng)的語句,語法格式如下:

IF condition THEN

??Statement

ELSELF condition THEN

??statement

ELSE

??statement

END IF

IF實(shí)現(xiàn)了一個(gè)基本的條件構(gòu)造,如果condition求值為真,響應(yīng)的SQL語句列表被執(zhí)行;如果沒有condition匹配,則ELSE字句里的語句列表被執(zhí)行。Statement可以包括一個(gè)或多個(gè)語句。如果非常熟悉Shell變量應(yīng)該很好理解這些語句,另外MySQL中還有一個(gè)IF()函數(shù),它不同于這里描述的IF語句。

示例

mysql> use testdb;

mysql> delimiter $

mysql> create procedure pif(n int,j char(1))

begin

?????? if j='gao' then

???????? select * from testdb.info where salary > n;

?????? else

???????? select * from testdb.info where salary < n;

?????? end if;

end$

該示例中,create procedure pif(n int,j char(1))語句怎么使用在創(chuàng)建函數(shù)中有說明,IF主要是判斷j參數(shù)的值,如果為“gao”那么執(zhí)行第一條SQL語句,如果j的值不等“gao”那么就執(zhí)行第二條SQL語句,IF語句都需要使用END IF來結(jié)束。

mysql> call pif(5000,'gao');

#調(diào)用存儲(chǔ)過程pif并輸入?yún)?shù)n和j的值

2)CASE語句

CASE是另一個(gè)進(jìn)行條件判斷的語句,該語句有2中語句格式,第1種格式如下:

CASE case_expr

WHEN when_value THEN statement

[WHEN when_value THEN statement]

[ELSE statement]

END CASE

其中,case_expr參數(shù)表示條件判斷的表達(dá)式,決定了那一個(gè)WHEN子句會(huì)被執(zhí)行;when_value參數(shù)表示表達(dá)式可能的值,如果某個(gè)when_value表達(dá)式與case_expr表達(dá)式結(jié)果相同,則執(zhí)行對應(yīng)THEN關(guān)鍵字后的statement中的語句;statement參數(shù)表示不同when_value值的執(zhí)行語句。

示例

mysql> create procedure caseone()

begin

??declare val INT;

??set val = 1;

??case val

? when 1 then select 'val is 1';

? when 2 then select 'val is 2';

? else select 'val is not 1 or 2';

??end case;

end$

mysql> call caseone()\G

*************************** 1. row ***************************

val is 1: val is 1

使用CASE判斷當(dāng)val值為1時(shí),輸出字符串“val is 1”;當(dāng)val值為2時(shí),輸出字符串“val is 2”;否則輸出字符串“val is not 1 or 2”。

CASE語句的第二種格式如下:

CASE

WHEN condition THEN statement

[WHEN condition THEN statement]

[ELSE statement]

END CASE

其中,condition參數(shù)表示條件判斷語句;statement參數(shù)表示不同條件的執(zhí)行語句。該語句中,WHEN語句將被逐個(gè)執(zhí)行,直到某個(gè)condition表達(dá)式為真,則執(zhí)行對應(yīng)THEN關(guān)鍵字后面的statement語句。如果沒有條件匹配,ELSE字句里的語句被執(zhí)行。

示例

mysql> create procedure casetwo ()

begin

??declare val INT;

??case

? when val IS NULL then select 'val is null';

? when val < 0 then select 'val is less than 0';

? when val > 0 then select 'val is greater than 0';

? else select 'val is 0';

??end case;

end$


mysql> call casetwo()\G

*************************** 1. row ***************************

val is null: val is null

當(dāng)val值為空,輸出字符串“val is NULL”;當(dāng)val值小于0時(shí),輸出字符串“val is less than 0”;當(dāng)val值大于0時(shí),輸出字符串“val is greater than 0”;否則輸出字符串“val is 0”。

3)LOOP語句

LOOP循環(huán)語句用來重復(fù)執(zhí)行某些語句,與IF和CASE語句相比,LOOP只是創(chuàng)建一個(gè)循環(huán)操作的過程,并不進(jìn)行條件判斷。LOOP內(nèi)的語句一直重復(fù)執(zhí)行直到循環(huán)被退出,跳出循環(huán)過程,使用LEAVE子句,LOOP語句的基本格式如下:

[loop_label:] LOOP

Statement

END LOOP [loop_label]

其中,loop_label表示LOOP語句的標(biāo)注名稱,該參數(shù)可以省略;statement參數(shù)表示需要循環(huán)執(zhí)行的語句。

示例

mysql> create procedure loopone()

begin

??declare id int default 0;

??add_loop:loop

? set id = id+1;

? if id >= 10 then leave add_loop;

? end if;

??end loop add_loop;

end$

4)LEAVE語句

LEAVE語句用來退出任何被標(biāo)注的流程控制構(gòu)造,LEAVE語句基本格式如下:

LEAVE label

其中,label參數(shù)表示循環(huán)的標(biāo)志,LEAVE和BEGIN….END或循環(huán)一起使用。使用LEAVE語句退出循環(huán),代碼如下:

Add_num:loop

Set @count=@count+1;

If @count=50 then leave add_num;

End loop add_num;

該循環(huán)執(zhí)行count加1的操作,當(dāng)count的值等于50時(shí),使用LEAVE語句跳出循環(huán)。

5)ITERATE語句

ITERATE語句將執(zhí)行順序轉(zhuǎn)到語句段開頭處,語句基本格式如下:

ITERATE label

Iterate只可以出現(xiàn)在LOOP、REPEAT和WHILE語句內(nèi)。Iterate的意思為“在此循環(huán)”,label參數(shù)表示循環(huán)的標(biāo)志。Iterate語句必須跟在循環(huán)標(biāo)志前面。

示例

mysql> create procedure iterateone()

begin

declare var int default 0;

my_loop:loop

? set var=var+1;

? if var < 10 then iterate my_loop;

? elseif var > 20 then leave my_loop;

? end if;

? select 'var is between 10 and 20';

end loop my_loop;

end$

var等于0,如果var的值小于10時(shí),重復(fù)執(zhí)行var加1操作;當(dāng)var大于等于10并且小于20時(shí),打印消息“var is between 10 and 20”;當(dāng)var大于20時(shí),退出循環(huán)。

6)REPEAT語句

REPEAT語句創(chuàng)建一個(gè)帶條件判斷的循環(huán)過程,每次語句執(zhí)行完畢之后,會(huì)對條件表達(dá)式進(jìn)行判斷,如果表達(dá)式為真,則循環(huán)結(jié)束;否則重復(fù)執(zhí)行循環(huán)中的語句。Repeat語句的基本格式如下:

[repeat_label]:REPEAT

Statement

UNTIL condition

End REPEAT [repeat_label]

示例:id值小于等于0之前,將重復(fù)執(zhí)行循環(huán)過程。

mysql> create procedure repeatone()

begin

declare id int default 0;

repeat

?? set id = id+1;

until id >= 10

end repeat;

select id;

mysql> call repeatone()\G

*************************** 1. row ***************************

id: 10

?7)WHILE語句

WHILE語句創(chuàng)建一個(gè)帶條件判斷的循環(huán)過程,與REPEAT不同,WHILE在執(zhí)行語句時(shí),先對指定的表達(dá)式進(jìn)行判斷,如果為真,則執(zhí)行循環(huán)內(nèi)的語句,否則退出循環(huán)。WHILE語句的基本格式如下:

[while_label:]WHILE condition DO

Statement

END WHILE [while_label]

while_label為WHILE語句的標(biāo)注名稱,condition為進(jìn)行判斷的表達(dá)式,如果表達(dá)式結(jié)果為真,WHILE語句內(nèi)的語句或語句群被執(zhí)行,直至condition為假,退出循環(huán)。

示例:使用WHILE計(jì)算1+n的和

create procedure whileone(n smallint)

begin

declare i int;

declare s int;

set i = 1;

set s = 0;

while i <= n do

set s = s + i;

set i = i + 1;

end while;

select s;

end$

mysql> delimiter ;

mysql> call whileone(10)\G

*************************** 1. row ***************************

s: 55

光標(biāo)的使用

查詢語句可能返回多條記錄,如果數(shù)據(jù)量非常大,需要在存儲(chǔ)過程和存儲(chǔ)函數(shù)中使用光標(biāo)來逐條讀取查詢結(jié)果集中的記錄。在存儲(chǔ)過程中可以使用光標(biāo)對結(jié)果集進(jìn)行循環(huán)處理,應(yīng)用程序可以根據(jù)需要滾動(dòng)或?yàn)g覽其中的數(shù)據(jù)。光標(biāo)必須在聲明處理程序之前被聲明,并且變量和條件還必須在聲明光標(biāo)或處理程序之前被聲明。

1)聲明光標(biāo)

MySQL中使用DECLARE關(guān)鍵字來聲明光標(biāo),其語法的基本形式如下:

DECLARE cursor_name CURSOR FOR select_statement

其中,cursor_name參數(shù)表示光標(biāo)的名稱;select_statement參數(shù)表示SELECT語句的內(nèi)容,返回一個(gè)用于創(chuàng)建光標(biāo)的結(jié)果集。

聲明名稱為cursor_first的光標(biāo),代碼如下:

DECLARE cursor_first CURSOR FOR select * from testdb.info;

2)打開光標(biāo)

OPEN cursor_first;

3)讀取光標(biāo)

FETCH cursor_name INTO var_name [,var_name]…{參數(shù)名稱}

這個(gè)語句用指定的打開光標(biāo)讀取下一行,并且前進(jìn)光標(biāo)指針。其中,cursor_name參數(shù)表示光標(biāo)的名稱;var_name參數(shù)表示將光標(biāo)中的SELECT語句查詢出來的信息存入該參數(shù)中,var_name必須在聲明光標(biāo)之前就定義好。

使用名稱為cursor_first的光標(biāo),將查詢出來的數(shù)據(jù)存入one_name和two_name這兩個(gè)變量中,代碼如下:

FETCH cursor_first INTO one_name,two_name;

4)關(guān)閉光標(biāo)

CLOSE cursor_name

這個(gè)語句關(guān)閉先前打開的光標(biāo),如果未被明確地關(guān)閉,光標(biāo)在它被聲明的復(fù)合語句的末尾被關(guān)閉。

PS:MySQL中光標(biāo)只能在存儲(chǔ)過程和存儲(chǔ)函數(shù)中使用。

示例1:把testdb.info中ID字段的值賦給光標(biāo)mycursor,然后把mycursor讀取到變量a上,最后使用LOOP循環(huán)顯示a變量

mysql> delimiter $

mysql> CREATE PROCEDURE curdemo()

BEGIN

DECLARE a INT;

DECLARE mycursor CURSOR FOR SELECT ID FROM testdb.info;

OPEN mycursor;

LOOP

??FETCH mycursor INTO a;

??SELECT a;

END LOOP;

CLOSE mycursor;

END $


mysql> call curdemo()$

mysql> delimiter ;

調(diào)用存儲(chǔ)過程

存儲(chǔ)過程是通過CALL語句進(jìn)行調(diào)用的,語法如下:

CALL procedure_name([parameter])

CALL語句調(diào)用一個(gè)先前用CREATE PROCEDURE創(chuàng)建的存儲(chǔ)過程,其中procedure_name為存儲(chǔ)過程的名稱,[parameter]為存儲(chǔ)過程的參數(shù),可選。下面頂一個(gè)countproc的存儲(chǔ)過程,然后調(diào)用這個(gè)存儲(chǔ)過程,代碼執(zhí)行如下:

mysql> delimiter $

mysql> create procedure countproc(IN sid INT,OUT num INT)

????begin

??????select count(*) into num from testdb.info where salary > 5000;

?????? end$

調(diào)用存儲(chǔ)過程

mysql> delimiter ;

mysql> call countproc(5000,@num);

查看返回結(jié)果

mysql> select @num\G

*************************** 1. row ***************************

@num: 3

該存儲(chǔ)過程返回了info表中工資高于5000的人數(shù),把人數(shù)返回值存儲(chǔ)在num變量中,使用SELECT查看,返回結(jié)果為3.

查看存儲(chǔ)過程和存儲(chǔ)函數(shù)

SHOW STATUS語句可以查看存儲(chǔ)過程和函數(shù)的狀態(tài),其基本語法結(jié)構(gòu)如下:

SHOW {PROCEDURE | FUNCTION} STATUS [LIKE ‘pattern’]

這個(gè)語句是一個(gè)MySQL的擴(kuò)展,它返回子程序的特征,如數(shù)據(jù)庫、名字、類型、創(chuàng)建者及創(chuàng)建和修改日期。如果沒有指定樣式,根據(jù)使用的語句,所有存儲(chǔ)程序或存儲(chǔ)函數(shù)的信息都被列出PROCEDURE和FUNCTION分別表示查看存儲(chǔ)過程和函數(shù);LIKE語句表示匹配存儲(chǔ)過程或函數(shù)的名稱。代碼執(zhí)行如下:

mysql> SHOW PROCEDURE STATUS LIKE 'var%'\G

*************************** 1. row ***************************

Db: testdb

Name: var

Type: PROCEDURE

Definer: root@localhost

Modified: 2015-11-17 22:40:58

Created: 2015-11-17 22:40:58

Security_type: DEFINER

Comment:

character_set_client: utf8

collation_connection: utf8_general_ci

Database Collation: utf8_general_ci

除了SHOW STATUS之外,MySQL還可以使用SHOW CREATE語句查看存儲(chǔ)過程和函數(shù)的狀態(tài)。

SHOW CREATE {PROCEDURE | FUNCTION} name

這個(gè)語句時(shí)一個(gè)MySQL的擴(kuò)展,類似于SHOW CREATE TABLE,它返回一個(gè)可用來重新創(chuàng)建已命名子程序的確切字符串。PROCEDURE和FUNCTION分別表示查看存儲(chǔ)過程和函數(shù);LIKE語句表示匹配存儲(chǔ)過程或函數(shù)的名稱。SHOW CREATE語句示例,代碼如下:

mysql> show create procedure var \G

*************************** 1. row ***************************

Procedure: var

sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION

Create Procedure: CREATE DEFINER=`root`@`localhost` PROCEDURE `var`()

begin

DECLARE var INT;

select count(*) into var from testdb.info;

end

character_set_client: utf8

collation_connection: utf8_general_ci

Database Collation: utf8_general_ci

MySQL中存儲(chǔ)過程和函數(shù)的信息存儲(chǔ)在information_schema數(shù)據(jù)庫下的Routines表中。可以通過查詢該表的記錄來查詢存儲(chǔ)過程和函數(shù)的信息。其基本語句形式如下:

select * from information_schema.Routines where ROUTINE_NAME='sp_name'\G

其中,ROUTINE_NAME字段中存儲(chǔ)的是存儲(chǔ)過程和函數(shù)的名稱;sp_name參數(shù)表示存儲(chǔ)過程或函數(shù)的名稱。從Routines表中查詢名稱為var的存儲(chǔ)函數(shù)的信息,代碼如下:

mysql> select * from information_schema.Routines where ROUTINE_NAME='var' AND ROUTINE_TYPE='PROCEDURE'\G

*************************** 1. row ***************************

SPECIFIC_NAME: var

ROUTINE_CATALOG: def

ROUTINE_SCHEMA: testdb

ROUTINE_NAME: var

ROUTINE_TYPE: PROCEDURE

DATA_TYPE:

CHARACTER_MAXIMUM_LENGTH: NULL

CHARACTER_OCTET_LENGTH: NULL

NUMERIC_PRECISION: NULL

NUMERIC_SCALE: NULL

DATETIME_PRECISION: NULL

CHARACTER_SET_NAME: NULL

COLLATION_NAME: NULL

DTD_IDENTIFIER: NULL

ROUTINE_BODY: SQL

ROUTINE_DEFINITION: begin

DECLARE var INT;

select count(*) into var from testdb.info;

end

EXTERNAL_NAME: NULL

EXTERNAL_LANGUAGE: NULL

PARAMETER_STYLE: SQL

IS_DETERMINISTIC: NO

SQL_DATA_ACCESS: MODIFIES SQL DATA

SQL_PATH: NULL

SECURITY_TYPE: INVOKER

CREATED: 2015-11-17 22:40:58

LAST_ALTERED: 2015-11-18 16:42:48

SQL_MODE: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION

ROUTINE_COMMENT:

DEFINER: root@localhost

CHARACTER_SET_CLIENT: utf8

COLLATION_CONNECTION: utf8_general_ci

DATABASE_COLLATION: utf8_general_ci

在information_schema數(shù)據(jù)庫下的Routines表中,存儲(chǔ)所有存儲(chǔ)過程和函數(shù)的定義。使用SELECT語句查詢Routines表中的存儲(chǔ)過程和函數(shù)的定義時(shí),一定要使用ROUTINE_NAME字段指定存儲(chǔ)過程或函數(shù)的名稱。否則,將查詢出所有的存儲(chǔ)過程或函數(shù)的定義。如果有存儲(chǔ)過程和存儲(chǔ)函數(shù)名稱相同,則需要同時(shí)指定ROUTINE_TYPE字段表明查詢的是哪種類型的存儲(chǔ)程序。

修改存儲(chǔ)過程和函數(shù)

使用ALTER語句可以修改存儲(chǔ)過程或函數(shù)的特性,語法如下:

ALTER {PROCEDURE | FUNCTION} sp_name [characteristic…]

其中,sp_name參數(shù)表示存儲(chǔ)過程或函數(shù)的名稱,characteristic參數(shù)指定存儲(chǔ)函數(shù)的特性,可能的取值有:

CONTAINS SQL – 表示子程序包含SQL語句,但不包含讀或?qū)憯?shù)據(jù)的語句。

NO SQL – 表示子程序中不包含SQL語句。

READS SQL DATA – 表示子程序中包含讀數(shù)據(jù)的語句。

MODIFIES SQL DATA – 表示子程序中包含寫數(shù)據(jù)的語句。

SQL SECURITY { DEFINER | INVOKER } – 指明誰有權(quán)限來執(zhí)行。

DEFINER – 表示只有定義者自己才能夠執(zhí)行。

INVOKER – 表示調(diào)用者可以執(zhí)行。

COMMENT ‘string’ – 表示注釋信息。

下面修改存儲(chǔ)過程

mysql> delimiter $

mysql> ALTER PROCEDURE countproc

-> MODIFIES SQL DATA

-> SQL SECURITY INVOKER

-> $

mysql> delimiter ;

存儲(chǔ)過程中的代碼可以修改嗎?MySQL目前還不支持對已存在的存儲(chǔ)過程代碼的更改。如果必須要更改存儲(chǔ)過程,必須使用DROP語句刪除之后,再重新寫代碼。

轉(zhuǎn)自:http://www.ywnds.com/?p=3877

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內(nèi)容