MySQL存儲過程


一、存儲過程簡介

  常用的操作數據庫語言SQL語句在執行的時候需要要先編譯,然后執行,而存儲過程是一組為了完成特定功能的SQL語句集,經編譯后存儲在數據庫中,用戶通過指定存儲過程的名字並給定參數(如果該存儲過程帶有參數)來調用執行它。
  一個存儲過程是一個可編程的函數,它在數據庫中創建並保存。它可以有 SQL 語句和一些特殊的控制結構組成。當希望在不同的應用程序或平台上執行相同的函數,或者封裝特定功能時,存儲過程是非常有用的。數據庫中的存儲過程可以看做是對編程中面向對象方法的模擬。它允許控制數據的訪問方式。

 

  通俗一點解釋上面的內容:存儲過程相對於數據庫類似於編程語言中的函數,可以傳入參數,可以調用多個 sql 語句,事先聲明好,之后再進行調用。並且不同編程語言都可以調用,相當於是聲明了一個多語言通用版的函數

存儲過程通常有以下優點:

  1. 存儲過程增強了SQL語言的功能和靈活性。存儲過程可以用流控制語句編寫,有很強的靈活性,可以完成復雜的判斷和較復雜的運算。
  2. 存儲過程允許標准組件是編程。存儲過程被創建后,可以在程序中被多次調用,而不必重新編寫該存儲過程的SQL語句。而且數據庫專業人員可以隨時對存儲過程進行修改,對應用程序源代碼毫無影響。
  3. 存儲過程能實現較快的執行速度。如果某一操作包含大量的 Transaction-SQL 代碼或分別被多次執行,那么存儲過程要比批處理的執行速度快很多。因為存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,並且給出最終被存儲在系統表中的執行計划。而批處理的 Transaction-SQL 語句在每次運行時都要進行編譯和優化,速度相對要慢一些。
  4. 存儲過程能過減少網絡流量。針對同一個數據庫對象的操作(如查詢、修改),如果這一操作所涉及的 Transaction-SQL 語句被組織程存儲過程,那么當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大增加了網絡流量並降低了網絡負載。
  5. 存儲過程可被作為一種安全機制來充分利用。系統管理員通過執行某一存儲過程的權限進行限制,能夠實現對相應的數據的訪問權限的限制,避免了非授權用戶對數據的訪問,保證了數據的安全。

 

二、關於存儲過程

  存儲過程是數據庫存儲的一個重要的功能,但是 MySQL 在 5.0 以前並不支持存儲過程,這使得 MySQL 在應用上大打折扣。好在 MySQL 5.0 終於開始已經支持存儲過程,這樣即可以大大提高數據庫的處理速度,同時也可以提高數據庫編程的靈活性。

 

三、存儲過程的創建

舉個簡單的例子進行說明

use test;                      -- 選擇使用的數據庫
delimiter //                   -- 將 MySQL 中以 ;(分號) 結尾的規定修改為以 //(雙斜杠) 為語句結束符
create procedure test_proce()  -- 創建一個名為test_proce的存儲過程
begin                          -- begin和end之間為存儲過程被執行時要做的SQL
insert into weuse(name,created_at,updated_at) values('hello',now(),now());
end//
delimiter ;                    -- 將 MySQL 中結束符重新改回默認(分號)

注:DELIMITER 是分割符的意思,因為 MySQL 默認以";"為結束符,如果沒有聲明結束符,那么編譯器會把存儲過程當成SQL語句進行處理,則存儲過程的編譯過程會報錯,所以要事先用 DELIMITER 關鍵字申明當前段分隔符,這樣 MySQL 才會將";"當做存儲過程中的代碼,不會執行這些代碼,用完了之后要把結束符還原,可以看到最后一行有對應的修改回來的語句。

 

帶參數的存儲過程創建格式

CREATE PROCEDURE([[IN |OUT |INOUT ] 參數名 數據類形...])
  • IN 輸入參數:表示該參數的值必須在調用存儲過程時指定,在存儲過程中修改該參數的值不能被返回,為默認值(看過去相當於函數的形參,但是不能被返回)
  • OUT 輸出參數:該值可在存儲過程內部被改變,並可返回(相當於函數內部變量)
  • INOUT 輸入輸出參數:調用時指定,並且可被改變和返回(相當於函數形參)
-- 創建帶有IN參數的存儲過程
DELIMITER // 
CREATE PROCEDURE demo_in_parameter(IN p_in int) 
BEGIN  
SELECT p_in;  
SET p_in=2;  
SELECT p_in;  
END;  
// 
DELIMITER ;

-- 執行結果
mysql > SET @p_in=1; 
mysql > CALL demo_in_parameter(@p_in); 
    +------+ 
    | p_in | 
    +------+ 
    |   1  |  
    +------+ 
    
    +------+ 
    | p_in | 
    +------+ 
    |   2  |  
    +------+ 
    
mysql> SELECT @p_in; 
    +-------+ 
    | @p_in | 
    +-------+ 
    |  1    | 
    +-------+ 


-- 以上可以看出,p_in雖然在存儲過程中被修改,但並不影響@p_id的值
帶有 IN 參數的存儲過程的例子
-- 創建
DELIMITER // 
CREATE PROCEDURE demo_out_parameter(OUT p_out int) 
BEGIN
SELECT p_out; 
SET p_out=2; 
SELECT p_out; 
END; 
 // 
DELIMITER ;


-- 執行結果:
mysql > SET @p_out=1; 
mysql > CALL sp_demo_out_parameter(@p_out); 
    +-------+ 
    | p_out |  
    +-------+ 
    | NULL  |  
    +-------+ 
    
    +-------+ 
    | p_out | 
    +-------+ 
    |   2   |  
    +-------+ 
    
mysql> SELECT @p_out; 
    +-------+ 
    | p_out | 
    +-------+ 
    |   2   | 
    +-------+ 
帶有 OUT 參數的存儲過程的例子
-- 創建:
DELIMITER //  
CREATE PROCEDURE demo_inout_parameter(INOUT p_inout int)  
BEGIN
SELECT p_inout; 
SET p_inout=2; 
SELECT p_inout;  
END; 
//  
DELIMITER ;


-- 執行結果:
mysql > SET @p_inout=1; 
mysql > CALL demo_inout_parameter(@p_inout) ; 
    +---------+ 
    | p_inout | 
    +---------+ 
    |    1    | 
    +---------+ 
    
    +---------+ 
    | p_inout |  
    +---------+ 
    |    2    | 
    +---------+ 
    
    mysql > SELECT @p_inout; 
    +----------+ 
    | @p_inout |  
    +----------+ 
    |    2     | 
    +----------+
帶有 INOUT 參數的存儲過程的例子

 

變量

定義變量的格式:datatype 為 MySQL 的數據類型,如:int,、float、 date,、varchar(length)

DECLARE variable_name [,variable_name...] datatype [DEFAULT value]; -- datatype 為 MySQL 的數據類型,如:int,、float、 date,、varchar(length)

-- 例如:
    DECLARE l_int int unsigned default 4000000; 
    DECLARE l_numeric number(8,2) DEFAULT 9.95; 
    DECLARE l_date date DEFAULT '1999-12-31'; 
    DECLARE l_datetime datetime DEFAULT '1999-12-31 23:59:59'; 
    DECLARE l_varchar varchar(255) DEFAULT 'This will not be padded';  

 

變量賦值

SET 變量名 = 表達式值 [,variable_name = expression ...]

 

用戶變量

  用戶變量通常以@開頭

注意:濫用用戶變量會導致程序難以理解及管理

mysql > SELECT 'Hello World' into @x; 
mysql > SELECT @x; 
    +-------------+ 
    |   @x        | 
    +-------------+ 
    | Hello World | 
    +-------------+ 
    mysql > SET @y='Goodbye Cruel World'; 
    mysql > SELECT @y; 
    +---------------------+ 
    |     @y              | 
    +---------------------+ 
    | Goodbye Cruel World | 
    +---------------------+ 
    
mysql > SET @z=1+2+3; 
mysql > SELECT @z; 
    +------+ 
    | @z   | 
    +------+ 
    |  6   | 
    +------+ 
ⅰ. 在MySQL客戶端使用用戶變量
mysql > CREATE PROCEDURE GreetWorld( ) SELECT CONCAT(@greeting,' World'); 
mysql > SET @greeting='Hello'; 
mysql > CALL GreetWorld( ); 
    +----------------------------+ 
    | CONCAT(@greeting,' World') | 
    +----------------------------+ 
    |  Hello World               | 
    +----------------------------+ 
ⅱ. 在存儲過程中使用用戶變量
mysql> CREATE PROCEDURE p1()   SET @last_procedure='p1'; 
mysql> CREATE PROCEDURE p2() SELECT CONCAT('Last procedure was ',@last_proc); 
mysql> CALL p1( ); 
mysql> CALL p2( ); 
    +-----------------------------------------------+ 
    | CONCAT('Last procedure was ',@last_proc  | 
    +-----------------------------------------------+ 
    | Last procedure was p1                         | 
    +-----------------------------------------------+ 
ⅲ. 在存儲過程間傳遞全局范圍的用戶變量

 

四、存儲過程的調用

  與函數類似,函數的調用是函數名(參數),存儲過程的調用只在前面多加一個 CALL,也就是 CALL 存儲過程(參數)

 

五、存儲過程的查詢

查看某個數據庫下面的存儲過程

-- 方式一
select name from mysql.proc where db=’數據庫名’;
-- 方式二
select routine_name from information_schema.routines where routine_schema='數據庫名';
-- 方式三
show procedure status where db='數據庫名';

 

查看某個存儲過程的詳細

-- 方式一
SHOW CREATE PROCEDURE 數據庫.存儲過程名;
-- 方式二
select body from mysql.proc where specific_name = 存儲過程名';

 

 

六、存儲過程的修改

ALTER PROCEDURE
-- 更改用CREATE PROCEDURE 建立的預先指定的存儲過程,其不會影響相關存儲過程或存儲功能。

 

七、存儲過程的刪除

DROP PROCEDURE 存儲過程名

 

八、存儲過程相關控制語句

1. 變量作用域

  內部的變量在其作用域范圍內享有更高的優先權,當執行到end。變量時,內部變量消失,此時已經在其作用域外,變量不再可見了,應為在存儲過程外再也不能找到這個申明的變量,但是可以通過 out 參數或者將其值指派給會話變量來保存其值。

DELIMITER // 
CREATE PROCEDURE proc3() 
begin
declare x1 varchar(5) default 'outer'; 
begin
declare x1 varchar(5) default 'inner'; 
select x1; 
end; 
select x1; 
end; 
// 
DELIMITER ; 
View Code

 

2. 條件語句

DELIMITER // 
CREATE PROCEDURE proc2(IN parameter int) 
begin
declare var int; 
set var=parameter+1; 
if var=0 then
insert into t values(17); 
end if; 
if parameter=0 then
update t set s1=s1+1; 
else
update t set s1=s1+2; 
end if; 
end; 
// 
DELIMITER ; 
Ⅰ. if-then -else語句
DELIMITER // 
CREATE PROCEDURE proc3 (in parameter int) 
begin
declare var int; 
set var=parameter+1; 
case var 
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; 
//
DELIMITER ;
Ⅱ. case語句:

 

3. 循環語句

DELIMITER // 
CREATE PROCEDURE proc4() 
begin
declare var int; 
set var=0; 
while var<6 do 
insert into t values(var); 
set var=var+1; 
end while; 
end; 
// 
DELIMITER ;
Ⅰ. while ···· end while:
-- 它在執行操作后檢查結果,而while則是執行前進行檢查。

DELIMITER // 
CREATE PROCEDURE proc5 () 
begin  
declare v int; 
set v=0; 
repeat 
insert into t values(v); 
set v=v+1; 
until v>=5 
end repeat; 
end; 
// 
DELIMITER ; 
Ⅱ. repeat···· end repeat:
-- loop循環不需要初始條件,這點和while 循環相似,同時和repeat循環一樣不需要結束條件, leave語句的意義是離開循環。
DELIMITER // 
CREATE PROCEDURE proc6 () 
begin
declare v int; 
set v=0; 
LOOP_LABLE:loop 
insert into t values(v); 
set v=v+1; 
if v >=5 then
leave LOOP_LABLE; 
end if; 
end loop; 
end; 
// 
DELIMITER ; 
Ⅲ. loop ·····end loop:

 

4. ITERATE迭代

  通過引用復合語句的標號,來從新開始復合語句

DELIMITER // 
CREATE PROCEDURE proc10 () 
begin
declare v int; 
set v=0; 
LOOP_LABLE:loop 
if v=3 then  
set v=v+1; 
ITERATE LOOP_LABLE; 
end if; 
insert into t values(v); 
set v=v+1; 
if v>=5 then
leave LOOP_LABLE; 
end if; 
end loop; 
end; 
// 
DELIMITER ;
View Code

 

九、存儲過程的基本函數

1. 字符串類

CHARSET(str)                                    -- 返回字串字符集
CONCAT (string2 [,... ])                        -- 連接字串
INSTR (string ,substring )                      -- 返回substring首次在string中出現的位置,不存在返回0
LCASE (string2 )                                -- 轉換成小寫
LEFT (string2 ,length )                         -- 從string2中的左邊起取length個字符
LENGTH (string )                                -- string長度
LOAD_FILE (file_name )                          -- 從文件讀取內容
LOCATE (substring , string [,start_position ] ) -- 同INSTR,但可指定開始位置
LPAD (string2 ,length ,pad )                    -- 重復用pad加在string開頭,直到字串長度為length
LTRIM (string2 )                                -- 去除前端空格
REPEAT (string2 ,count )                        -- 重復count次
REPLACE (str ,search_str ,replace_str )         -- 在str中用replace_str替換search_str
RPAD (string2 ,length ,pad)                     -- 在str后用pad補充,直到長度為length
RTRIM (string2 )                                -- 去除后端空格
STRCMP (string1 ,string2 )                      -- 逐字符比較兩字串大小,
SUBSTRING (str , position [,length ])           -- 從str的position開始,取length個字符,

注:mysql中處理字符串時,默認第一個字符下標為1,即參數position必須大於等於1

select substring('abcd',0,2); 
    +-----------------------+ 
    | substring('abcd',0,2) | 
    +-----------------------+ 
    |                       | 
    +-----------------------+ 
    1 row in set (0.00 sec) 
    
    mysql> select substring('abcd',1,2); 
    +-----------------------+ 
    | substring('abcd',1,2) | 
    +-----------------------+ 
    |     ab                | 
    +-----------------------+ 
    1 row in set (0.02 sec) 

TRIM([[BOTH|LEADING|TRAILING] [padding] FROM]string2) -- 去除指定位置的指定字符
UCASE (string2 ) -- 轉換成大寫
RIGHT(string2,length) -- 取string2最后length個字符
SPACE(count) -- 生成count個空格
View Code

 

2. 數字類

ABS (number2 )                   -- 絕對值
BIN (decimal_number )            -- 十進制轉二進制
CEILING (number2 )               -- 向上取整
CONV(number2,from_base,to_base)  -- 進制轉換
FLOOR (number2 )                 -- 向下取整
FORMAT (number,decimal_places )  -- 保留小數位數
HEX (DecimalNumber )             -- 轉十六進制。注:HEX()中可傳入字符串,則返回其ASC-11碼,如HEX('DEF')返回4142143,也可以傳入十進制整數,返回其十六進制編碼,如HEX(25)返回19
LEAST (number , number2 [,..])   -- 求最小值
MOD (numerator ,denominator )    -- 求余
POWER (number ,power )           -- 求指數
RAND([seed])                     -- 隨機數
ROUND (number [,decimals ])      -- 四舍五入,decimals為小數位數]

 

3. 日期時間類

ADDTIME (date2 ,time_interval )             -- 將time_interval加到date2
CONVERT_TZ (datetime2 ,fromTZ ,toTZ )       -- 轉換時區
CURRENT_DATE ( )                            -- 當前日期
CURRENT_TIME ( )                            -- 當前時間
CURRENT_TIMESTAMP ( )                       -- 當前時間戳
DATE (datetime )                            -- 返回datetime的日期部分
DATE_ADD (date2 , INTERVAL d_value d_type ) -- 在date2中加上日期或時間
DATE_FORMAT (datetime ,FormatCodes )        -- 使用formatcodes格式顯示datetime
DATE_SUB (date2 , INTERVAL d_value d_type ) -- 在date2上減去一個時間
DATEDIFF (date1 ,date2 )                    -- 兩個日期差
DAY (date )                                 -- 返回日期的天
DAYNAME (date )                             -- 英文星期
DAYOFWEEK (date )                           -- 星期(1-7) ,1為星期天
DAYOFYEAR (date )                           -- 一年中的第幾天
EXTRACT (interval_name FROM date )          -- 從date中提取日期的指定部分
MAKEDATE (year ,day )                       -- 給出年及年中的第幾天,生成日期串
MAKETIME (hour ,minute ,second )            -- 生成時間串
MONTHNAME (date )                           -- 英文月份名
NOW ( )                                     -- 當前時間
SEC_TO_TIME (seconds )                      -- 秒數轉成時間
STR_TO_DATE (string ,format )               -- 字串轉成時間,以format格式顯示
TIMEDIFF (datetime1 ,datetime2 )            -- 兩個時間差
TIME_TO_SEC (time )                         -- 時間轉秒數]
WEEK (date_time [,start_of_week ])          -- 第幾周
YEAR (datetime )                            -- 年份
DAYOFMONTH(datetime)                        -- 月的第幾天
HOUR(datetime)                              -- 小時
LAST_DAY(date)                              -- date的月的最后日期
MICROSECOND(datetime)                       -- 微秒
MONTH(datetime)                             --
MINUTE(datetime)                            -- 分返回符號,正負或0
SQRT(number2)                               -- 開平方

 

 

 

 

 

 參考:https://www.iteye.com/blog/xdj651897373-126-com-1819924

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM