一. 存儲過程的定義:
存儲過程(Stored Procedure)是在大型數據庫系統中,一組為了完成特定功能的SQL 語句集,經編譯后存儲在數據庫中,用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。
二. 存儲過程的優點:
- 簡化應用開發人員的工作。當用不同語言編寫多客戶應用程序,或多客戶應用程序在不同平台上運行且需要執行相同的數據庫操作之時。
- 增強安全性。比如,銀行對所有普通操作使用存儲程序。這提供一個堅固而安全的環境,程序可以確保每一個操作都被妥善記入日志。在這樣一個設置中,應用程序和用戶不可能直接訪問數據庫表,但是僅可以執行指定的存儲程序。
- 減少數據在數據庫和應用服務器之間的傳輸。
三.存儲過程的權限
- 使用權限:
CREATE ROUTINE 建立存儲過程
EXECUTE 運行存儲過程
CREATE PROCEDURE p()
SQL SECURITY INVOKER創建存儲過程中有一個特征子句可以讓存儲過程使用運行者的權限
CREATE PROCEDURE p()
SQL SECURITY DEFINER 默認值
四. 存儲過程的創建
CREATE PROCEDURE sp_name ([proc_parameter[,...]])
[characteristic ...] routine_body
默認地,子程序與當前數據庫關聯。要明確地把子程序與一個給定數據庫關聯起來,可以在創建子程序的時候指定其名字為db_name.sp_name。
sp_name 存儲過程的名字proc_parameter指定參數為IN, OUT,或INOUTcharacteristic 特征routine_body 包含合法的SQL過程語句。
in 把數據從外部傳遞給存儲過程
out 從存儲過程內部返回值給外部使用者
inout 把數據傳遞給存儲過程和將存儲過程的返回值傳遞給外部使用者
示例:
五. 存儲過程的刪除
DROP PROCEDURE [IF EXISTS] sp_name
這個語句被用來移除一個存儲程序或函數。即,從服務器移除一個制定的子程序。在MySQL 5.1中,你必須有ALTER ROUTINE權限才可用此子程序。這個權限被自動授予子程序的創建者。IF EXISTS 子句是一個MySQL的擴展。如果程序或函數不存在,它防止發生錯誤。示例:DROP PROCEDURE IF EXISTS `Proc_Notify_UserfavDiscount_Mail2`$$
六. 存儲過程的狀態
SHOW PROCEDURE STATUS ;顯示數據庫中所有存儲的存儲過程基本信息
show create procedure procedure_name;顯示某一個存儲過程的創建語句
delimiter // /*改變輸入結束符*/
DROP PROCEDURE IF EXISTS sp_test //
CREATE PROCEDURE sp_test /* 存儲過程名 */
(IN inparms INT,OUT outparams varchar(32)) /* 輸入參數 */
BEGIN /* 語句塊頭 */
DECLARE var CHAR(10); /* 變量聲明 */
DECLARE num int;
IF inparms = 1 THEN /* IF條件開始*/
SET var = 'hello'; /* 賦值 */
ELSE
SET var = 'world';
END IF; /* IF結束 */
INSERT INTO t1 VALUES (var); /* SQL語句 */
select count(*) from t1 into num;
SELECT name FROM t1 LIMIT num, 1 INTO outparams;
END
//
delimiter ;
call sp_test(1, @out);
Select @out;
事先創建表
create table t1(id int not null auto_increment,name varchar(45),primary key pk_id (id));
七. 存儲過程的變量
聲明變量:
DECLARE var_name[,...] type [DEFAULT value] → 這個語句被用來聲明局部變量。如果要給變量提供一個默認值,需要 包含一個DEFAULT子句。值可以被指定為一個表達式,不需要為一個常 數。如果沒有DEFAULT子句,初始值為NULL。 → 局部變量的作用范圍在它被聲明的BEGIN ... END塊內。示例:DECLARE fromDate DATETIMEDECLARE nHour INTDECLARE v_exit INT DEFAULT 0
八. 變量賦值
變量賦值,可以直接賦值,或者通過查詢賦值
語句:
SET var_name = expr [, var_name = expr] ...select col_name into var_name[,...] table_expr
示例:SET nowDate=NOW();SET a.fanli_discount = b.max_fanli;select count(*) into num from table1 where price=100;
九. BEGIN...END復合語句
[begin_label:] BEGIN [statement_list] END [end_label]
存儲子程序可以使用BEGIN ... END復合語句來包含多個語句。statement_list 代表一個或多個語句的列表。statement_list之內每個語句都必須用分號(;)來結尾。 復合語句可以被標記。除非begin_label存在,否則end_label不能被給出,並且如果二者都存在,他們必須是同樣的。 使用多重語句需要客戶端能發送包含語句定界符;的查詢字符串。這個符號在命令行客戶端被用delimiter命令來處理。改變查詢結尾定界符;(比如改變為//)使得; 可被用在子程序體中。舉例:
LOOP … END LOOP示例:CREATE PROCEDURE p5 ()BEGIN DECLARE v INT; SET v = 0; loop_label: LOOP INSERT INTO t VALUES (v); SET v = v + 1; IF v >= 5 THEN LEAVE loop_label; END IF; END LOOP;END //[begin_label:] LOOP statement_listEND LOOP [end_label]LOOP允許某特定語句或語句群的重復執行,實現一個簡單的循環構造。在循環內的語句一直重復直到循環被退出,退出通常伴隨着一個LEAVE 語句。
DELIMITER //
CREATE PROCEDURE p1(IN parameter1 INT)
BEGIN
DECLARE variable1 INT;
SET variable1 = parameter1 + 1;
IF variable1 = 0 THEN
INSERT INTO t VALUES (17);
END IF;
IF parameter1 = 0 THEN
UPDATE t SET s1 = s1 + 1;
ELSE
UPDATE t SET s1 = s1 + 2;
END IF;
END //
DELIMITER ;
十. 流程控制
IF語句
IF search_condition THEN statement_list [ELSEIF search_condition THEN statement_list] ... [ELSE statement_list] END IF
IF實現了一個基本的條件構造。如search_condition求值為真,相應的SQL語句列表被執行。如果沒有search_condition匹配,在ELSE子句里的語句列表被執行。
statement_list可以包括一個或多個語句。
十一. CASE語句
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語句實現一個復雜的條件構造。如果search_condition 求值為真,相應的SQL被執行。如果沒有搜索條件匹配,在ELSE子句里的語句被執行。
示例:
delimiter //CREATE PROCEDURE p2 (IN parameter1 INT)BEGIN DECLARE variable1 INT; SET variable1 = parameter1 + 1; CASE variable1 WHEN 0 THEN INSERT INTO t VALUES (17); WHEN 1 THEN INSERT INTO t VALUES (18); ELSE INSERT INTO t VALUES (19); END CASE;END//
十二. 循環語句
WHILE … END WHILE示例:delimiter //CREATE PROCEDURE p4 ()BEGIN DECLARE v INT; SET v = 0; WHILE v < 5 DO INSERT INTO t VALUES (v); SET v = v + 1; END WHILE;END //十三. 補充:迭代(ITERATE)語句
CREATE PROCEDURE p7 ()BEGIN DECLARE v INT; SET v = 0; loop_label: LOOP IF v = 3 THEN SET v = v + 1; ITERATE loop_label; END IF; INSERT INTO t VALUES (v); SET v = v + 1; IF v >= 5 THEN LEAVE loop_label; END IF; END LOOP;END //十四. 注釋語法:
mysql存儲過程可使用兩種風格的注釋雙模杠:--,該風格一般用於單行注釋c風格:/* 注釋內容 */, 一般用於多行注釋DELIMITER $$ USE `51fanli_cang`$$ DROP PROCEDURE IF EXISTS `Proc_Notify_UserfavDiscount_Mail2`$$ CREATE DEFINER=`root`@`%` PROCEDURE `Proc_Notify_UserfavDiscount_Mail2`(IN latestPushTime DATETIME) BEGIN DROP TEMPORARY TABLE IF EXISTS tmp_Userfav_Discount_Cnt; CREATE TEMPORARY TABLE tmp_Userfav_Discount_Cnt AS SELECT a.user_id, COUNT(a.id) COUNT, ROUND(SUM(a.price) - SUM(b.pricenow), 2) diffprice FROM fav_userfav a INNER JOIN fav_product b ON a.product_id = b.id WHERE a.is_del = 0 AND a.price_flg = 2 AND a.in_buy = 0 AND b.pricedown_time >= latestPushTime GROUP BY a.user_id; SELECT user_id,user_name,user_email,topic_title,link_pic,price,link_value,source_title,pricenow,shop_id,source_pic,COUNT,diffprice,rank FROM ( SELECT user_id,user_name,user_email,topic_title,link_pic,price,link_value,source_title,pricenow,shop_id,source_pic,COUNT,diffprice,@rownum:=@rownum+1, IF(@pdept=heyf_tmp.user_id,@rank:=@rank+1,@rank:=1) AS rank, @pdept:=heyf_tmp.user_id FROM ( SELECT a.user_id ,a.topic_title,a.link_pic,a.price,b.link_value,b.source_title,b.pricenow,b.shop_id,b.source_pic,c.count,c.diffprice,d.user_name,d.user_email FROM fav_userfav a INNER JOIN fav_product b ON a.product_id=b.id INNER JOIN tmp_Userfav_Discount_Cnt c ON a.user_id=c.user_id INNER JOIN fav_user d ON d.user_id = c.user_id WHERE a.is_del = 0 AND a.price_flg = 2 AND a.in_buy = 0 AND d.user_email IS NOT NULL ORDER BY a.user_id,b.pricedown_time,a.price - b.pricenow DESC ) heyf_tmp ,(SELECT @rownum :=0 , @pdept := NULL ,@rank:=0) a ) result WHERE rank<=5; END$$ DELIMITER ;