下面一些情況下存儲程序尤其有用:
· 當用不同語(yǔ)言編寫(xiě)多客戶(hù)應用程序,或多客戶(hù)應用程序在不同平臺上運行且需要執行相同的數據庫操作之時(shí)。
· 安全極為重要之時(shí)。比如,銀行對所有普通操作使用存儲程序。這提供一個(gè)堅固而安全的環(huán)境,程序可以確保每一個(gè)操作都被妥善記入日志。在這樣一個(gè)設置中,應用程序和用戶(hù)不可能直接訪(fǎng)問(wèn)數據庫表,但是僅可以執行指定的存儲程序。
存儲程序可以提供改良后的性能,因為只有較少的信息需要在服務(wù)器和客戶(hù)算之間傳送。代價(jià)是增加數據庫服務(wù)器系統的負荷,因為更多的工作在服務(wù)器這邊完成,更少的在客戶(hù)端(應用程序)那邊完成上。如果許多客戶(hù)端機器(比如網(wǎng)頁(yè)服務(wù)器)只由一個(gè)或少數幾個(gè)數據庫服務(wù)器提供服務(wù),可以考慮一下存儲程序。
存儲程序也允許你在數據庫服務(wù)器上有函數庫。這是一個(gè)被現代應用程序語(yǔ)言共享的特征,它允許這樣的內部設計,比如通過(guò)使用類(lèi)。使用這些客戶(hù)端應用程序語(yǔ)言特征對甚至于數據庫使用范圍以外的編程人員都有好處。
MySQL為存儲程序遵循SQL:2003語(yǔ)法,這個(gè)語(yǔ)法也被用在IBM的DB2數據庫上。
MySQL對存儲程序的實(shí)現還在進(jìn)度中。所有本章敘述的語(yǔ)法都被支持,在有限制或擴展的地方會(huì )恰當地指出來(lái)。有關(guān)使用存儲程序的限制的更多討論在附錄 I, 特性限制里提到。
如20.4節,“存儲子程序和觸發(fā)程序的二進(jìn)制日志功能”里所說(shuō)的,存儲子程序的二進(jìn)制日志功能已經(jīng)完成。
存儲程序需要在mysql數據庫中有proc表。這個(gè)表在MySQL 5.1安裝過(guò)程中創(chuàng )建。如果你從早期的版本升級到MySQL 5.1 ,請確定更新你的授權表以確保proc表的存在。請參閱2.10.2節 “升級授權表”。
在MySQL 5.1中,授權系統如下考慮存儲子程序:
· 創(chuàng )建存儲子程序需要CREATE ROUTINE權限。
· 提醒或移除存儲子程序需要ALTER ROUTINE權限。這個(gè)權限自動(dòng)授予子程序的創(chuàng )建者。
· 執行子程序需要EXECUTE權限。然而,這個(gè)權限自動(dòng)授予子程序的創(chuàng )建者。同樣,子程序默認的SQL SECURITY 特征是DEFINER,它允許用該子程序訪(fǎng)問(wèn)數據庫的用戶(hù)與執行子程序聯(lián)系到一起。
20.2.1. CREATE PROCEDURE和CREATE FUNCTION
20.2.2. ALTER PROCEDURE和ALTER FUNCTION
20.2.3. DROP PROCEDURE和DROP FUNCTION
20.2.4. SHOW CREATE PROCEDURE和SHOW CREATE FUNCTION
存儲程序和函數是用CREATE PROCEDURE和CREATE FUNCTION語(yǔ)句創(chuàng )建的子程序。一個(gè)子程序要么是一個(gè)程序要么是一個(gè)函數。使用CALL語(yǔ)句來(lái)調用程序,程序只能用輸出變量傳回值。就像別其它函數調用一樣,函數可以被從語(yǔ)句外調用(即通過(guò)引用函數名),函數能返回標量值。存儲子程序也可以調用其它存儲子程序。
在MySQL 5.1中,一個(gè)存儲子程序或函數與特定的數據庫相聯(lián)系。這里有幾個(gè)意思:
· 當一個(gè)子程序被調用時(shí),一個(gè)隱含的USE db_name 被執行(當子程序終止時(shí)停止執行)。存儲子程序內的USE語(yǔ)句時(shí)不允許的。
· 你可以使用數據庫名限定子程序名。這可以被用來(lái)引用一個(gè)不在當前數據庫中的子程序。比如,要引用一個(gè)與test數據庫關(guān)聯(lián)的存儲程序p或函數f,你可以說(shuō)CALL test.p()或test.f()。
· 數據庫移除的時(shí)候,與它關(guān)聯(lián)的所有存儲子程序也都被移除。
MySQL 支持非常有用的擴展,即它允許在存儲程序中使用常規的SELECT語(yǔ)句(那就是說(shuō),不使用光標或局部變量)。這個(gè)一個(gè)查詢(xún)的結果包被簡(jiǎn)單地直接送到客戶(hù)端。多SELECT語(yǔ)句生成多個(gè)結果包,所以客戶(hù)端必須使用支持多結果包的MySQL客戶(hù)端庫。這意味這客戶(hù)端必須使用至少MySQL 4.1以來(lái)的近期版本上的客戶(hù)端庫。
下面一節描述用來(lái)創(chuàng )建,改變,移除和查詢(xún)存儲程序和函數的語(yǔ)法。
CREATE PROCEDURE sp_name ([proc_parameter[,...]])
[characteristic ...] routine_body CREATE FUNCTION sp_name ([func_parameter[,...]]) RETURNS type [characteristic ...] routine_body proc_parameter: [ IN | OUT | INOUT ] param_name type func_parameter: param_name type type:
Any valid MySQL data type characteristic:
LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER } | COMMENT 'string' routine_body:
Valid SQL procedure statement or statements這些語(yǔ)句創(chuàng )建存儲子程序。要在MySQL 5.1中創(chuàng )建子程序,必須具有CREATE ROUTINE權限,并且ALTER ROUTINE和EXECUTE權限被自動(dòng)授予它的創(chuàng )建者。如果二進(jìn)制日志功能被允許,你也可能需要SUPER權限,請參閱20.4節,“存儲子程序和觸發(fā)程序的二進(jìn)制日志功能”。
默認地,子程序與當前數據庫關(guān)聯(lián)。要明確地把子程序與一個(gè)給定數據庫關(guān)聯(lián)起來(lái),可以在創(chuàng )建子程序的時(shí)候指定其名字為db_name.sp_name。
如果子程序名和內建的SQL函數名一樣,定義子程序時(shí),你需要在這個(gè)名字和隨后括號中間插入一個(gè)空格,否則發(fā)生語(yǔ)法錯誤。當你隨后調用子程序的時(shí)候也要插入。為此,即使有可能出現這種情況,我們還是建議最好避免給你自己的存儲子程序取與存在的SQL函數一樣的名字。
由括號包圍的參數列必須總是存在。如果沒(méi)有參數,也該使用一個(gè)空參數列()。每個(gè)參數默認都是一個(gè)IN參數。要指定為其它參數,可在參數名之前使用關(guān)鍵詞 OUT或INOUT
注意: 指定參數為IN, OUT, 或INOUT 只對PROCEDURE是合法的。(FUNCTION參數總是被認為是IN參數)
RETURNS字句只能對FUNCTION做指定,對函數而言這是強制的。它用來(lái)指定函數的返回類(lèi)型,而且函數體必須包含一個(gè)RETURN value語(yǔ)句。
routine_body 包含合法的SQL過(guò)程語(yǔ)句??梢允褂脧秃险Z(yǔ)句語(yǔ)法,請參閱20.2.7節,“BEGIN ... END復合語(yǔ)句”。復合語(yǔ)句可以包含聲明,循環(huán)和其它控制結構語(yǔ)句。這些語(yǔ)句的語(yǔ)法在本章后免介紹,舉例,請參閱20.2.8節,“DECLARE語(yǔ)句”和20.2.12節,“流程控制構造”。
CREATE FUNCTION語(yǔ)句被用在更早的MySQL版本上以支持UDF (自定義函數)。請參閱27.2節,“給MySQL添加新函數”。 UDF繼續被支持,即使現在有了存儲函數。UDF會(huì )被認為一個(gè)外部存儲函數。然而,不要讓存儲函數與UDF函數共享名字空間。
外部存儲程序的框架將在不久的將來(lái)引入。這將允許你用SQL之外的語(yǔ)言編寫(xiě)存儲程序。最可能的是,第一個(gè)被支持語(yǔ)言是PHP,因為核心PHP引擎很小,線(xiàn)程安全,且可以被方便地嵌入。因為框架是公開(kāi)的,它希望許多其它語(yǔ)言也能被支持。
如果程序或線(xiàn)程總是對同樣的輸入參數產(chǎn)生同樣的結果,則被認為它是“確定的”,否則就是“非確定”的。如果既沒(méi)有給定DETERMINISTIC也沒(méi)有給定NOT DETERMINISTIC,默認的就是NOT DETERMINISTIC。
為進(jìn)行復制,使用NOW()函數(或它的同義詞)或
當前來(lái)講,DETERMINISTIC特征被接受,但還沒(méi)有被優(yōu)化程序所使用。然而如果二進(jìn)制日志功能被允許了,這個(gè)特征影響到MySQL是否會(huì )接受子程序定義。請參閱20.4節,“存儲子程序和觸發(fā)程序的二進(jìn)制日志功能”。
一些特征提供子程序使用數據的內在信息。CONTAINS SQL表示子程序不包含讀或寫(xiě)數據的語(yǔ)句。NO SQL表示子程序不包含SQL語(yǔ)句。READS SQL DATA表示子程序包含讀數據的語(yǔ)句,但不包含寫(xiě)數據的語(yǔ)句。MODIFIES SQL DATA表示子程序包含寫(xiě)數據的語(yǔ)句。如果這些特征沒(méi)有明確給定,默認的是CONTAINS SQL。
SQL SECURITY特征可以用來(lái)指定 子程序該用創(chuàng )建子程序者的許可來(lái)執行,還是使用調用者的許可來(lái)執行。默認值是DEFINER。在SQL:2003中者是一個(gè)新特性。創(chuàng )建者或調用者必須由訪(fǎng)問(wèn)子程序關(guān)聯(lián)的數據庫的許可。在MySQL 5.1中,必須有EXECUTE權限才能執行子程序。必須擁有這個(gè)權限的用戶(hù)要么是定義者,要么是調用者,這取決于SQL SECURITY特征是如何設置的。
MySQL存儲sql_mode系統變量設置,這個(gè)設置在子程序被創(chuàng )建的時(shí)候起作用,MySQL總是強制使用這個(gè)設置來(lái)執行子程序。
COMMENT子句是一個(gè)MySQL的擴展,它可以被用來(lái)描述存儲程序。這個(gè)信息被SHOW CREATE PROCEDURE和 SHOW CREATE FUNCTION語(yǔ)句來(lái)顯示。
MySQL允許子程序包含DDL語(yǔ)句,如CREATE和DROP。MySQL也允許存儲程序(但不是存儲函數)包含SQL 交互語(yǔ)句,如COMMIT。存儲函數不可以包含那些做明確的和絕對的提交或者做回滾的語(yǔ)。SQL標準不要求對這些語(yǔ)句的支持,SQL標準聲明每個(gè)DBMS提供商可以決定是否允許支持這些語(yǔ)句。
存儲子程序不能使用LOAD DATA INFILE。
返回結果包的語(yǔ)句不能被用在存儲函數種。這包括不使用INTO給變量讀取列值的SELECT語(yǔ)句,SHOW 語(yǔ)句,及其它諸如EXPLAIN這樣的語(yǔ)句。對于可在函數定義時(shí)間被決定要返回一個(gè)結果包的語(yǔ)句,發(fā)生一個(gè)允許從函數錯誤返回結果包的Not(ER_SP_NO_RETSET_IN_FUNC)。對于只可在運行時(shí)決定要返回一個(gè)結果包的語(yǔ)句, 發(fā)生一個(gè)不能在給定上下文錯誤返回結果包的PROCEDURE %s (ER_SP_BADSELECT)。
下面是一個(gè)使用OUT參數的簡(jiǎn)單的存儲程序的例子。例子為,在程序被定義的時(shí)候,用mysql客戶(hù)端delimiter命令來(lái)把語(yǔ)句定界符從 ;變?yōu)?/。這就允許用在程序體中的;定界符被傳遞到服務(wù)器而不是被mysql自己來(lái)解釋。
mysql> delimiter // mysql> CREATE PROCEDURE simpleproc (OUT param1 INT) -> BEGIN -> SELECT COUNT(*) INTO param1 FROM t; -> END -> //Query OK, 0 rows affected (0.00 sec) mysql> delimiter ; mysql> CALL simpleproc(@a);Query OK, 0 rows affected (0.00 sec) mysql> SELECT @a;+------+| @a |+------+| 3 |+------+1 row in set (0.00 sec)當使用delimiter命令時(shí),你應該避免使用反斜杠(‘\’)字符,因為那是MySQL的轉義字符。
下列是一個(gè)例子,一個(gè)采用參數的函數使用一個(gè)SQL函數執行一個(gè)操作,并返回結果:
mysql> delimiter // mysql> CREATE FUNCTION hello (s CHAR(20)) RETURNS CHAR(50) -> RETURN CONCAT('Hello, ',s,'!'); -> //Query OK, 0 rows affected (0.00 sec) mysql> delimiter ; mysql> SELECT hello('world');+----------------+| hello('world') |+----------------+| Hello, world! |+----------------+1 row in set (0.00 sec)如果在存儲函數中的RETURN語(yǔ)句返回一個(gè)類(lèi)型不同于在函數的RETURNS子句中指定類(lèi)型的值,返回值被強制為恰當的類(lèi)型。比如,如果一個(gè)函數返回一個(gè)ENUM或SET值,但是RETURN語(yǔ)句返回一個(gè)整數,對于SET成員集的相應的ENUM成員,從函數返回的值是字符串。
ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]
characteristic:
{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER } | COMMENT 'string'這個(gè)語(yǔ)句可以被用來(lái)改變一個(gè)存儲程序或函數的特征。在MySQL 5.1中,你必須用ALTER ROUTINE權限才可用此子程序。這個(gè)權限被自動(dòng)授予子程序的創(chuàng )建者。如20.4節,“存儲子程序和觸發(fā)程序的二進(jìn)制日志功能”中所述, 如果二進(jìn)制日志功能被允許了,你可能也需要SUPER權限。
在A(yíng)LTER PROCEDURE和ALTER FUNCTION語(yǔ)句中,可以指定超過(guò)一個(gè)的改變。
DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name
這個(gè)語(yǔ)句被用來(lái)移除一個(gè)存儲程序或函數。即,從服務(wù)器移除一個(gè)制定的子程序。在MySQL 5.1中,你必須有ALTER ROUTINE權限才可用此子程序。這個(gè)權限被自動(dòng)授予子程序的創(chuàng )建者。
IF EXISTS 子句是一個(gè)MySQL的擴展。如果程序或函數不存儲,它防止發(fā)生錯誤。產(chǎn)生一個(gè)可以用SHOW WARNINGS查看的警告。
SHOW CREATE {PROCEDURE | FUNCTION} sp_name
這個(gè)語(yǔ)句是一個(gè)MySQL的擴展。類(lèi)似于SHOW CREATE TABLE,它返回一個(gè)可用來(lái)重新創(chuàng )建已命名子程序的確切字符串。
mysql> SHOW CREATE FUNCTION test.hello\G*************************** 1. row *************************** Function: hello sql_mode:Create Function: CREATE FUNCTION `test`.`hello`(s CHAR(20)) RETURNS CHAR(50)RETURN CONCAT('Hello, ',s,'!')SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']
這個(gè)語(yǔ)句是一個(gè)MySQL的擴展。它返回子程序的特征,如數據庫,名字,類(lèi)型,創(chuàng )建者及創(chuàng )建和修改日期。如果沒(méi)有指定樣式,根據你使用的語(yǔ)句,所有存儲程序和所有存儲函數的信息都被列出。
mysql> SHOW FUNCTION STATUS LIKE 'hello'\G*************************** 1. row *************************** Db: test Name: hello Type: FUNCTION Definer: testuser@localhost Modified: 2004-08-03 15:29:37 Created: 2004-08-03 15:29:37Security_type: DEFINER Comment:你可以從INFORMATION_SCHEMA中的ROUTINES表獲得有關(guān)存儲子程序的信息。請參閱23.1.14節,“INFORMATION_SCHEMA ROUTINES 表”。
CALL sp_name([parameter[,...]])
CALL語(yǔ)句調用一個(gè)先前用CREATE PROCEDURE創(chuàng )建的程序。
CALL語(yǔ)句可以用聲明為OUT或的INOUT參數的參數給它的調用者傳回值。它也“返回”受影響的行數,客戶(hù)端程序可以在SQL級別通過(guò)調用ROW_COUNT()函數獲得這個(gè)數,從C中是調用the mysql_affected_rows() C API函數來(lái)獲得。
[begin_label:] BEGIN
[statement_list]END [end_label]存儲子程序可以使用BEGIN ... END復合語(yǔ)句來(lái)包含多個(gè)語(yǔ)句。statement_list 代表一個(gè)或多個(gè)語(yǔ)句的列表。statement_list之內每個(gè)語(yǔ)句都必須用分號(;)來(lái)結尾。
復合語(yǔ)句可以被標記。除非begin_label存在,否則end_label不能被給出,并且如果二者都存在,他們必須是同樣的。
請注意,可選的[NOT] ATOMIC子句現在還不被支持。這意味著(zhù)在指令塊的開(kāi)始沒(méi)有交互的存儲點(diǎn)被設置,并且在上下文中用到的BEGIN子句對當前交互動(dòng)作沒(méi)有影響。
使用多重語(yǔ)句需要客戶(hù)端能發(fā)送包含語(yǔ)句定界符;的查詢(xún)字符串。這個(gè)符號在命令行客戶(hù)端被用delimiter命令來(lái)處理。改變查詢(xún)結尾定界符;(比如改變?yōu)?/)使得; 可被用在子程序體中。
DECLARE語(yǔ)句被用來(lái)把不同項目局域到一個(gè)子程序:局部變量(請參閱20.2.9節,“存儲程序中的變量”),條件和處理程序(請參閱20.2.10節,“條件和處理程序”) 及光標(請參閱20.2.11節,“光標”)。SIGNAL和RESIGNAL語(yǔ)句當前還不被支持。
DECLARE僅被用在BEGIN ... END復合語(yǔ)句里,并且必須在復合語(yǔ)句的開(kāi)頭,在任何其它語(yǔ)句之前。
光標必須在聲明處理程序之前被聲明,并且變量和條件必須在聲明光標或處理程序之前被聲明。
你可以在子程序中聲明并使用變量。
DECLARE var_name[,...] type [DEFAULT value]這個(gè)語(yǔ)句被用來(lái)聲明局部變量。要給變量提供一個(gè)默認值,請包含一個(gè)DEFAULT子句。值可以被指定為一個(gè)表達式,不需要為一個(gè)常數。如果沒(méi)有DEFAULT子句,初始值為NULL。
局部變量的作用范圍在它被聲明的BEGIN ... END塊內。它可以被用在嵌套的塊中,除了那些用相同名字聲明變量的塊。
SET var_name = expr [, var_name = expr] ...
在存儲程序中的SET語(yǔ)句是一般SET語(yǔ)句的擴展版本。被參考變量可能是子程序內聲明的變量,或者是全局服務(wù)器變量。
在存儲程序中的SET語(yǔ)句作為預先存在的SET語(yǔ)法的一部分來(lái)實(shí)現。這允許SET a=x, b=y, ...這樣的擴展語(yǔ)法。其中不同的變量類(lèi)型(局域聲明變量及全局和集體變量)可以被混合起來(lái)。這也允許把局部變量和一些只對系統變量有意義的選項合并起來(lái)。在那種情況下,此選項被識別,但是被忽略了。
SELECT col_name[,...] INTO var_name[,...] table_expr
這個(gè)SELECT語(yǔ)法把選定的列直接存儲到變量。因此,只有單一的行可以被取回。
SELECT id,data INTO x,y FROM test.t1 LIMIT 1;注意,用戶(hù)變量名在MySQL 5.1中是對大小寫(xiě)不敏感的。請參閱9.3節,“用戶(hù)變量”。
重要: SQL變量名不能和列名一樣。如果SELECT ... INTO這樣的SQL語(yǔ)句包含一個(gè)對列的參考,并包含一個(gè)與列相同名字的局部變量,MySQL當前把參考解釋為一個(gè)變量的名字。例如,在下面的語(yǔ)句中,xname 被解釋為到xname variable 的參考而不是到xname column的:
CREATE PROCEDURE sp1 (x VARCHAR(5)) BEGIN DECLARE xname VARCHAR(5) DEFAULT 'bob'; DECLARE newname VARCHAR(5); DECLARE xid INT; SELECT xname,id INTO newname,xid FROM table1 WHERE xname = xname; SELECT newname; END;當這個(gè)程序被調用的時(shí)候,無(wú)論table.xname列的值是什么,變量newname將返回值‘bob’。
特定條件需要特定處理。這些條件可以聯(lián)系到錯誤,以及子程序中的一般流程控制。
DECLARE condition_name CONDITION FOR condition_value
condition_value:
SQLSTATE [VALUE] sqlstate_value | mysql_error_code這個(gè)語(yǔ)句指定需要特殊處理的條件。它將一個(gè)名字和指定的錯誤條件關(guān)聯(lián)起來(lái)。這個(gè)名字可以隨后被用在DECLARE HANDLER語(yǔ)句中。請參閱20.2.10.2節,“DECLARE處理程序”。
除了SQLSTATE值,也支持MySQL錯誤代碼。
DECLARE handler_type HANDLER FOR condition_value[,...] sp_statement
handler_type:
CONTINUE | EXIT | UNDO condition_value:
SQLSTATE [VALUE] sqlstate_value | condition_name | SQLWARNING | NOT FOUND | SQLEXCEPTION | mysql_error_code這個(gè)語(yǔ)句指定每個(gè)可以處理一個(gè)或多個(gè)條件的處理程序。如果產(chǎn)生一個(gè)或多個(gè)條件,指定的語(yǔ)句被執行。
對一個(gè)CONTINUE處理程序,當前子程序的執行在執行處理程序語(yǔ)句之后繼續。對于EXIT處理程序,當前BEGIN...END復合語(yǔ)句的執行被終止。UNDO 處理程序類(lèi)型語(yǔ)句還不被支持。
· SQLWARNING是對所有以01開(kāi)頭的SQLSTATE代碼的速記。
· NOT FOUND是對所有以02開(kāi)頭的SQLSTATE代碼的速記。
· SQLEXCEPTION是對所有沒(méi)有被SQLWARNING或NOT FOUND捕獲的SQLSTATE代碼的速記。
除了SQLSTATE值,MySQL錯誤代碼也不被支持。
例如:
mysql> CREATE TABLE test.t (s1 int,primary key (s1));Query OK, 0 rows affected (0.00 sec) mysql> delimiter // mysql> CREATE PROCEDURE handlerdemo () -> BEGIN -> DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; -> SET @x = 1; -> INSERT INTO test.t VALUES (1); -> SET @x = 2; -> INSERT INTO test.t VALUES (1); -> SET @x = 3; -> END; -> //Query OK, 0 rows affected (0.00 sec) mysql> CALL handlerdemo()//Query OK, 0 rows affected (0.00 sec) mysql> SELECT @x// +------+ | @x | +------+ | 3 | +------+ 1 row in set (0.00 sec)注意到,@x是3,這表明MySQL被執行到程序的末尾。如果DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; 這一行不在,第二個(gè)INSERT因PRIMARY KEY強制而失敗之后,MySQL可能已經(jīng)采取默認(EXIT)路徑,并且SELECT @x可能已經(jīng)返回2。
簡(jiǎn)單光標在存儲程序和函數內被支持。語(yǔ)法如同在嵌入的SQL中。光標當前是不敏感的,只讀的及不滾動(dòng)的。不敏感意為服務(wù)器可以活不可以復制它的結果表。
光標必須在聲明處理程序之前被聲明,并且變量和條件必須在聲明光標或處理程序之前被聲明。
例如:
CREATE PROCEDURE curdemo()BEGIN DECLARE done INT DEFAULT 0; DECLARE a CHAR(16); DECLARE b,c INT; DECLARE cur1 CURSOR FOR select id,data FROM test.t1; DECLARE cur2 CURSOR FOR select i FROM test.t2; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; OPEN cur1; OPEN cur2; REPEAT FETCH cur1 INTO a, b; FETCH cur2 INTO c; IF NOT done THEN IF b < c THEN INSERT INTO test.t3 VALUES (a,b); ELSE INSERT INTO test.t3 VALUES (a,c); END IF; END IF; UNTIL done END REPEAT; CLOSE cur1; CLOSE cur2;ENDDECLARE cursor_name CURSOR FOR select_statement這個(gè)語(yǔ)句聲明一個(gè)光標。也可以在子程序中定義多個(gè)光標,但是一個(gè)塊中的每一個(gè)光標必須有唯一的名字。
SELECT語(yǔ)句不能有INTO子句。
IF, CASE, LOOP, WHILE, ITERATE, 及 LEAVE 構造被完全實(shí)現。
這些構造可能每個(gè)包含要么一個(gè)單獨語(yǔ)句,要么是使用BEGIN ... END復合語(yǔ)句的一塊語(yǔ)句。構造可以被嵌套。
目前還不支持FOR循環(huán)。
IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ... [ELSE statement_list]END IFIF實(shí)現了一個(gè)基本的條件構造。如果search_condition求值為真,相應的SQL語(yǔ)句列表被執行。如果沒(méi)有search_condition匹配,在ELSE子句里的語(yǔ)句列表被執行。statement_list可以包括一個(gè)或多個(gè)語(yǔ)句。
CASE case_value
WHEN when_value THEN statement_list [WHEN when_value THEN statement_list] ... [ELSE statement_list]END CASEOr:
CASE WHEN search_condition THEN statement_list [WHEN search_condition THEN statement_list] ... [ELSE statement_list]END CASE存儲程序的CASE語(yǔ)句實(shí)現一個(gè)復雜的條件構造。如果search_condition 求值為真,相應的SQL被執行。如果沒(méi)有搜索條件匹配,在ELSE子句里的語(yǔ)句被執行。
注意:這里介紹的用在存儲程序里的CASE語(yǔ)句與12.2節,“控制流程函數”里描述的SQL CASE表達式的CASE語(yǔ)句有輕微不同。這里的CASE語(yǔ)句不能有ELSE NULL子句,并且用END CASE替代END來(lái)終止。
[begin_label:] LOOP
statement_listEND LOOP [end_label]LOOP允許某特定語(yǔ)句或語(yǔ)句群的重復執行,實(shí)現一個(gè)簡(jiǎn)單的循環(huán)構造。在循環(huán)內的語(yǔ)句一直重復直循環(huán)被退出,退出通常伴隨著(zhù)一個(gè)LEAVE 語(yǔ)句。
LOOP語(yǔ)句可以被標注。除非begin_label存在,否則end_label不能被給出,并且如果兩者都出現,它們必須是同樣的。
ITERATE label
ITERATE只可以出現在LOOP, REPEAT, 和WHILE語(yǔ)句內。ITERATE意思為:“再次循環(huán)。”
例如:
CREATE PROCEDURE doiterate(p1 INT)BEGIN label1: LOOP SET p1 = p1 + 1; IF p1 < 10 THEN ITERATE label1; END IF; LEAVE label1; END LOOP label1; SET @x = p1;END[begin_label:] REPEAT
statement_listUNTIL search_conditionEND REPEAT [end_label]REPEAT語(yǔ)句內的語(yǔ)句或語(yǔ)句群被重復,直至search_condition 為真。
REPEAT 語(yǔ)句可以被標注。 除非begin_label也存在,end_label才能被用,如果兩者都存在,它們必須是一樣的。
例如:
mysql> delimiter // mysql> CREATE PROCEDURE dorepeat(p1 INT) -> BEGIN -> SET @x = 0; -> REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT; -> END -> //Query OK, 0 rows affected (0.00 sec) mysql> CALL dorepeat(1000)//Query OK, 0 rows affected (0.00 sec) mysql> SELECT @x//+------+| @x |+------+| 1001 |+------+1 row in set (0.00 sec)[begin_label:] WHILE search_condition DO
statement_listEND WHILE [end_label]WHILE語(yǔ)句內的語(yǔ)句或語(yǔ)句群被重復,直至search_condition 為真。
WHILE語(yǔ)句可以被標注。 除非begin_label也存在,end_label才能被用,如果兩者都存在,它們必須是一樣的。
例如:
CREATE PROCEDURE dowhile()BEGIN DECLARE v1 INT DEFAULT 5; WHILE v1 > 0 DO ... SET v1 = v1 - 1; END WHILE;END
聯(lián)系客服