mysql 存儲過程學習筆記

Mysql存儲過程學習筆記css

1. 存儲過程簡介

經常使用的操做數據庫語言SQL語句在執行的時候須要要先編譯,而後執行,而存儲過程(Stored Procedure)是一組爲了完成特定功能的SQL語句集,經編譯後存儲在數據庫中,用戶經過指定存儲過程的名字並給定參數(若是該存儲過程帶有參數)來調用執行它。html

一個存儲過程是一個可編程的函數,它在數據庫中建立並保存。它能夠有SQL語句和一些特殊的控制結構組成。當但願在不一樣的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是很是有用的。數據庫中的存儲過程能夠看作是對編程中面向對象方法的模擬。它容許控制數據的訪問方式。前端

存儲過程一般有如下優勢:mysql

(1).存儲過程加強了SQL語言的功能和靈活性。存儲過程能夠用流控制語句編寫,有很強的靈活性,能夠完成複雜的判斷和較複雜的運算。sql

(2).存儲過程容許標準組件是編程。存儲過程被建立後,能夠在程序中被屢次調用,而沒必要從新編寫該存儲過程的SQL語句。並且數據庫專業人員能夠隨時對存儲過程進行修改,對應用程序源代碼毫無影響。數據庫

(3).存儲過程能實現較快的執行速度。若是某一操做包含大量的Transaction-SQL代碼或分別被屢次執行,那麼存儲過程要比批處理的執行速度快不少。由於存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,而且給出最終被存儲在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。express

(4).存儲過程能過減小網絡流量。針對同一個數據庫對象的操做(如查詢、修改),若是這一操做所涉及的Transaction-SQL語句被組織程存儲過程,那麼當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大增長了網絡流量並下降了網絡負載。編程

(5).存儲過程可被做爲一種安全機制來充分利用。系統管理員經過執行某一存儲過程的權限進行限制,可以實現對相應的數據的訪問權限的限制,避免了非受權用戶對數據的訪問,保證了數據的安全。後端

 

2.關於MySQL的存儲過程

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

3. MySQL存儲過程的建立

(1). 格式

MySQL存儲過程建立的格式:CREATE PROCEDURE 過程名 ([過程參數[,...]])

[特性 ...] 過程體

DELIMITER

CREATE PROCEDURE proc1(OUT s int

BEGIN

SELECT COUNT(*) INTO s FROM testSeq; 

END

DELIMITER

 

這裏先舉個例子:

 

 

 

注:

(1)這裏須要注意的是DELIMITER //和DELIMITER ;兩句,DELIMITER是分割符的意思,由於MySQL默認以";"爲分隔符,若是咱們沒有聲明分割符,那麼編譯器會把存儲過程當成SQL語句進行處理,則存儲過程的編譯過程會報錯,因此要事先用DELIMITER關鍵字申明當前段分隔符,這樣MySQL纔會將";"當作存儲過程當中的代碼,不會執行這些代碼,用完了以後要把分隔符還原。

(2)存儲過程根據須要可能會有輸入、輸出、輸入輸出參數,這裏有一個輸出參數s,類型是int型,若是有多個參數用","分割開。

(3)過程體的開始與結束使用BEGIN與END進行標識。

這樣,咱們的一個MySQL存儲過程就完成了,是否是很容易呢?看不懂也不要緊,接下來,咱們詳細的講解。

4.存儲過程參數:

MySQL存儲過程的參數用在存儲過程的定義,共有三種參數類型,IN,OUT,INOUT,形式如:

CREATE PROCEDURE([[IN |OUT |INOUT ] 參數名 數據類形...])

IN 輸入參數:表示該參數的值必須在調用存儲過程時指定,在存儲過程當中修改該參數的值不能被返回,爲默認值

OUT 輸出參數:該值可在存儲過程內部被改變,並可返回

INOUT 輸入輸出參數:調用時指定,而且可被改變和返回

小例子:

存儲過程爲:

 
 

DROP PROCEDURE IF EXISTS TestParameter;

CREATE PROCEDURE TestParameter(IN a INT,

                               INOUT b INT,

                               OUT c INT)

BEGIN

 SET a = a + 10;

 SET b = b + 10;

 SET c = b + 10;

END;

 

 

 

 

 

 

 

 

 

SET @a = 5;

SET @b = 6;

SET @c = 7;

CALL TestParameter(@a,@b,@c);

SELECT @a;

SELECT @b;

SELECT @c;

 

調用存儲過程:

 

 

 

 

 

 

 

 

 

5.變量

(1).變量定義:

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';  

(2).變量賦值

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

(3).變量做用域

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

 
 

DROP PROCEDURE IF EXISTS proc3

CREATE PROCEDURE proc3() 

 BEGIN

    DECLARE x1 VARCHAR(5) DEFAULT 'outer'; 

    BEGIN

        DECLARE x1 VARCHAR(5) DEFAULT 'inner'; 

        SELECT x1; 

    END; 

    SELECT x1; 

END;

 

 

 

 

 

 

 

 

 

6.定義條件和處理程序

定義條件和處理程序是事先定義程序執行過程當中可能遇到的問題。而且能夠在處理程序中定義解決這些問題的辦法。這種方式能夠提早預測可能出現的問題,並提出解決辦法。這樣能夠加強程序處理問題的能力,避免程序異常中止。MySQL中都是經過DECLARE關鍵字來定義條件和處理程序。本小節中將詳細講解如何定義條件和處理程序。

(1).定義條件

MySQL中可使用DECLARE關鍵字來定義條件。其基本語法以下:

 

DECLARE  condition_name  CONDITION  FOR  condition_value 

condition_value: 

      SQLSTATE [VALUE] sqlstate_value | mysql_error_code

其中,condition_name參數表示條件的名稱;condition_value參數表示條件的類型;sqlstate_value參數和mysql_error_code參數均可以表示MySQL的錯誤。例如ERROR 1146 (42S02)中,sqlstate_value值是42S02,mysql_error_code值是1146。

【示例】 下面定義"ERROR 1146 (42S02)"這個錯誤,名稱爲can_not_find。能夠用兩種不一樣的方法來定義,代碼以下:

//方法一:使用sqlstate_value 

DECLARE  can_not_find  CONDITION  FOR  SQLSTATE  '42S02' ; 

//方法二:使用mysql_error_code 

DECLARE  can_not_find  CONDITION  FOR  1146 ;

(2).定義處理程序

MySQL中可使用DECLARE關鍵字來定義處理程序。其基本語法以下:

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

其中,handler_type參數指明錯誤的處理方式,該參數有3個取值。這3個取值分別是CONTINUE、EXIT和UNDO。CONTINUE表示遇到錯誤不進行處理,繼續向下執行;EXIT表示遇到錯誤後立刻退出;UNDO表示遇到錯誤後撤回以前的操做,MySQL中暫時還不支持這種處理方式。

注意:一般狀況下,執行過程當中遇到錯誤應該馬上中止執行下面的語句,而且撤回前面的操做。可是,MySQL中如今還不能支持UNDO操做。

所以,遇到錯誤時最好執行EXIT操做。若是事先可以預測錯誤類型,而且進行相應的處理,那麼能夠執行CONTINUE操做。

 

condition_value參數指明錯誤類型,該參數有6個取值。sqlstate_value和mysql_error_code與條件定義中的是同一個意思。

 

condition_name是DECLARE定義的條件名稱。SQLWARNING表示全部以01開頭的sqlstate_value值。NOT FOUND表示全部以02開頭的

 

sqlstate_value值。SQLEXCEPTION表示全部沒有被SQLWARNING或NOT FOUND捕獲的sqlstate_value值。sp_statement表示一些存儲過程或函

 

數的執行語句。

 

【示例】 下面是定義處理程序的幾種方式。代碼以下:

 

//方法一:捕獲sqlstate_value 

DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'

SET @info='CAN NOT FIND'; 

//方法二:捕獲mysql_error_code 

DECLARE CONTINUE HANDLER FOR 1146 SET @info='CAN NOT FIND'; 

//方法三:先定義條件,而後調用 

DECLARE  can_not_find  CONDITION  FOR  1146 ; 

DECLARE CONTINUE HANDLER FOR can_not_find SET

@info='CAN NOT FIND'; 

//方法四:使用SQLWARNING 

DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR'; 

//方法五:使用NOT FOUND 

DECLARE EXIT HANDLER FOR NOT FOUND SET @info='CAN NOT FIND'; 

//方法六:使用SQLEXCEPTION 

DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info='ERROR';

上述代碼是6種定義處理程序的方法。

第一種方法是捕獲sqlstate_value值。若是遇到sqlstate_value值爲42S02,執行CONTINUE操做,而且輸出"CAN NOT FIND"信息。

第二種方法是捕獲mysql_error_code值。若是遇到mysql_error_code值爲1146,執行CONTINUE操做,而且輸出"CAN NOT FIND"信息。

第三種方法是先定義條件,而後再調用條件。這裏先定義can_not_find條件,遇到1146錯誤就執行CONTINUE操做。

第四種方法是使用SQLWARNING。SQLWARNING捕獲全部以01開頭的sqlstate_value值,而後執行EXIT操做,而且輸出"ERROR"信息。

第五種方法是使用NOT FOUND。NOT FOUND捕獲全部以02開頭的sqlstate_value值,而後執行EXIT操做,而且輸出"CAN NOT FIND"信息。

第六種方法是使用SQLEXCEPTION。SQLEXCEPTION捕獲全部沒有被SQLWARNING或NOT FOUND捕獲的sqlstate_value值,而後執行EXIT操做,而且輸出"ERROR"信息。

7.MySQL存儲過程的查詢

咱們像知道一個數據庫下面有那些表,咱們通常採用show tables;進行查看。那麼咱們要查看某個數據庫下面的存儲過程,是否也能夠採用呢?答案是,咱們能夠查看某個數據庫下面的存儲過程,可是是令一鍾方式。

咱們能夠用

select name from mysql.proc where db=’數據庫名’;

或者

select routine_name from information_schema.routines where routine_schema='數據庫名';

或者

show procedure status where db='數據庫名';

進行查詢。

若是咱們想知道,某個存儲過程的詳細,那咱們又該怎麼作呢?是否是也能夠像操做表同樣用describe 表名進行查看呢?

答案是:咱們能夠查看存儲過程的詳細,可是須要用另外一種方法:

SHOW CREATE PROCEDURE 數據庫.存儲過程名;

就能夠查看當前存儲過程的詳細。

 

 

8.MySQL存儲過程的刪除

刪除一個存儲過程比較簡單,和刪除表同樣:DROP PROCEDURE從MySQL的表格中刪除一個或多個存儲過程。

9.條件語句

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; 

 

(1). if-then -else語句

 

 

 

 

 

 

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; 

 

(2). case語句:

 

 

 

 

 

 

10.循環語句

 

 

CREATE PROCEDUER proc4()

BEIGIN

  DECLARE VAR INT;

  SET VAR = 0;

  WHILE VAR < 6 DO

    INSERT INTO T VLUES(VAR);

    SET VAR = VAR+1;

  END WHILE;

END;

 

(1).WHILE...END WHILE

 

 

 

 

(2).

CREATE PROCEDURE proc5()

  BEIGIN

    DECLARE v int;

    set v = 0;

    REPEAT

    INSERT INTO t VALUES(V);

    SET v = v+1;

  UNTIL V >=5

  END REPEAT;

END

 

REPEAT...END REPEAT

 

 

 

 

(3).LOOP...END LOOP:

CREATE PROCEDURE proc6()

BEIGIN

  DECLARE v int;

  SET v = 0;

  LOOP_LABLE:loop

    SET v = v+1;

    IF v >= 5 THEN

      LEAVE LOOP_LABLE;

    END IF;

  END LOOP;

END

 

LOOP 循環不須要初始條件,這點和WHILE循環類似,同時和REPEAT循環同樣不須要結束條件,LEAVE 語句的意思是離開循環

 

 

 

11.ITERATE迭代

(1).ITERATE:

經過引用符合語句的標號,來從新開始符合語句

 

 

CREATE PROCEDUER proc10()

BEIGIN

  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;

 

 

 

 

 

 

 

12.存儲過程的基本函數

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

TRIM([[BOTH|LEADING|TRAILING] [padding] FROM]string2) //去除指定位置的指定字符

UCASE (string2 ) //轉換成大寫

RIGHT(string2,length) //取string2最後length個字符

SPACE(count) //生成count個空格

 

(1).字符串類:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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爲小數位數]

 

 

(2).數學類

 

 

 

 

 

 

 

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

 

 

 (3).日期時間類

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/*MySql 的註釋*/

 

SELECT /*能夠在行中間註釋*/UTC_TIMESTAMP() a;

 

SELECT

/*也能夠

  多行

  註釋*/

UTC_TIMESTAMP() b;

 

#這個是單行註釋  一直到行尾

-- 這個也是單行註釋 一直到行尾

-- 注意「--」後必須有一個空格

 

13.關於註釋

 

 

 

 

 

 

 

 

DROP PROCEDURE IF EXISTS zhuTestProCursor;

CREATE PROCEDURE zhuTestProCursor()

BEGIN

 

  -- 定義變量 存放從遊標讀取的數據

  DECLARE AtempID INT;

  DECLARE AtempContent VARCHAR(200);

 

  -- 該變量記錄遊標中是否還有數據能夠讀取

  DECLARE no_more_data INT DEFAULT 0;

 

  DECLARE myCursor1 CURSOR FOR SELECT ID,CONTENT FROM zhucwTestTable;

  -- 若是沒有數據返回時程序繼續往下執行 並將 變量no_more_data 的值置爲1 

  DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_data=1;

 -- 這條語句必須放到定義遊標的語句下面

  -- 打開遊標

  OPEN  myCursor1;

  lblRepeat:REPEAT

    -- 讀取遊標內容 將ID和CONTENT值賦給對應暫存變量

    FETCH myCursor1 INTO AtempID,AtempContent;

    -- 沒有數據時跳出REPEAT 循環

    IF no_more_data = 1 THEN

    LEAVE lblRepeat;

    END IF;

    -- 將取到的數據插入到zhucwTest

    INSERT INTO zhucwTest2 (tempID,tempContent,tempDate) values (AtempID,AtempContent,UTC_TIMESTAMP());

    -- 當變量 no_more_data 的值爲0的時候跳出REPEAT循環

    UNTIL no_more_data

    END REPEAT lblRepeat;

  -- 關閉遊標

  CLOSE myCursor1; 

END

 

 

14學習遊標

 

 

 

 

 

 

 

 

 

 

 

 

 

DROP PROCEDURE IF EXISTS myProTestUseCursorTempTable;

CREATE PROCEDURE myProTestUseCursorTempTable()

/*

  使用遊標查詢表中數據,並將查詢的數據插入到臨時表中查詢出來

*/

BEGIN

  -- 定義暫存從遊標讀取內容的變量

  DECLARE tempID INT;

  DECLARE tempContent VARCHAR(50);

  DECLARE tempDate DATETIME DEFAULT UTC_TIMESTAMP();

  -- 記錄遊標是否還有內容的變量

  DECLARE no_more_data INT DEFAULT 0;

  -- 定義遊標

     DECLARE myCursor Cursor FOR SELECT ID,CONTENT FROM zhucwTestTable;

  -- 定義執行

  DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_data = 1;

  -- 定義臨時表

  CREATE TEMPORARY TABLE IF NOT EXISTS tbl_myProTestUseCursorTempTable0(

    fsID INT,

    fsContent VARCHAR(50),

    fsDate DATETIME,

    PRIMARY KEY(fsID)

  );

  -- 刪除臨時表中數據

  DELETE FROM tbl_myProTestUseCursorTempTable0;

   -- 打開遊標

  OPEN myCursor;

  -- 執行REPEAT 循環

  lblRepeat:REPEAT

    -- 讀取遊標信息,將信息給暫存變量

    FETCH myCursor INTO tempID,tempContent;

    -- 將暫存變量的值插入到臨時表中

    INSERT INTO tbl_myProTestUseCursorTempTable0 (fsID, fsContent , fsDate)

    VALUES (tempID ,tempContent ,tempDate);

    -- 若是遊標沒有數據 跳出循環體

    IF no_more_data THEN

    LEAVE lblRepeat;

    END IF;

  UNTIL no_more_data

  END  REPEAT lblRepeat;

  SELECT * from tbl_myProTestUseCursorTempTable0;

END

 

 

16.學習臨時表

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

17.實現mysql序列

 
 

 

/* 實現mysql序列  */

 

-- 1.建立一個含有一個自增加字段的表

DROP TABLE IF EXISTS testSeq;

CREATE TABLE testSeq(

  seq INT AUTO_INCREMENT NOT NULL PRIMARY KEY

)

-- 2.查詢最後一個插入的ID值

SELECT LAST_INSERT_ID();

-- 3. 向表中插入一個空值

INSERT INTO testSeq VALUES (NULL)

-- 4.查詢最後一個插入的ID值

SELECT LAST_INSERT_ID();

-- 5.向表中插入多個空值

INSERT INTO testSeq VALUES (NULL);

INSERT INTO testSeq VALUES (NULL);

INSERT INTO testSeq VALUES (NULL);

INSERT INTO testSeq VALUES (NULL);

-- 6.查詢最後一個插入的ID值

SELECT LAST_INSERT_ID();

-- 7.查詢seq的最大值

SELECT MAX(seq) FROM testSeq;

 

-- 8.具體也可用存儲過程實現更爲負責的序列

 

/*

  總結:若是有表想實現像ORACLE那樣的序列

        只需

        1.每次插入該表時再插入testSel一個NULL值

        2.查詢最後一個插入的ID值SELEC LAST_INSERT_ID

        或直接查詢MAX(seq)

 

*/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

18.學習函數

   
 

/*學習函數 實現1+2+3+...N的值*/

-- 若是函數名存在 則刪除該函數

DROP FUNCTION IF EXISTS zhuTestSum;

-- 建立函數參數爲INT類型 返回值也爲INT類型

CREATE FUNCTION zhuTestSum(gdate INT) RETURNS INT 

BEGIN 

  -- 定義返回變量  默認值爲0

  DECLARE result INT DEFAULT 0

  -- 定義循環變量 默認值爲0

  DECLARE ii INT DEFAULT 0;

 

  -- 若是參數值爲負數則返回 -1

  IF gdate < 0 THEN

    SET result = -1;

  -- 若是參數值爲0則返回0

  ELSEIF gdate = 0 THEN

    set result = 0;

  -- 若是參數值大於0則執行循環

  ELSE

    lblRepeat:REPEAT   

      -- 若是循環變量大於參數 跳出循環

      SET result = ii+result;

      SET ii = ii + 1;

    UNTIL ii > gdate

    END REPEAT lblRepeat;

  END IF;

RETURN result; 

END

 
 
 

DROP FUNCTION IF EXISTS zhuTestgetdate;

/*格式化日期*/

CREATE FUNCTION zhuTestgetdate(gdate datetime) RETURNS varchar(255)

BEGIN 

DECLARE x VARCHAR(255) DEFAULT ''; 

SET x= date_format(gdate,'%Y-%m-%d %h:%i:%s'); 

RETURN x; 

END;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

19.關於replace into

-- 測試replace into 函數

-- !!!注意使用此函數必須有主見或惟一標識

-- 此函數的做用是若是數據同樣不更新  不然更新該記錄

-- 新建一個測試表

DROP TABLE IF EXISTS zhucwTest0412;

create TABLE zhucwTest0412(

  id int,

  content1 varchar(10),

  content2 varchar(10),

  PRIMARY KEY(id)

)

 

-- 插入測試數據

 

insert into zhucwTest0412(id,content1,content2)

       values(1,"content1","content2");

 

SELECT * FROM zhucwTest0412;

 

insert into zhucwTest0412(id,content1,content2)

       values(1,"content1","content2");

      

SELECT * FROM zhucwTest0412;

      

replace into zhucwTest0412(id,content1,content2)

       values(1,"content11","content2");

      

SELECT * FROM zhucwTest0412;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                 

 

 

 

-- 學習PREPARE 20160418

 

SET @SQL1 = "SELECT * FROM tbluser LIMIT ?";-- 定義SQL語句

SET @p = 11; -- 定義變量

--  定義預處理語句

PREPARE executeSQL FROM @SQL1 ;

-- 執行預處理語句 將變量@p賦給佔位符?

EXECUTE executeSQL USING @p;

-- 刪除定義 釋放資源

DEALLOCATE  PREPARE executeSql;  

 

/*

 

注意事項

A:PREPARE stmt_name FROM preparable_stmt;預約義一個語句,並將它賦給 stmt_name ,tmt_name 是不區分大小寫的。

B: 即便 preparable_stmt 語句中的 ? 所表明的是一個字符串,你也不須要將 ? 用引號包含起來。

C: 若是新的 PREPARE 語句使用了一個已存在的 stmt_name ,那麼原有的將被當即釋放! 即便這個新的 PREPARE 語句由於錯誤而不能被正確執行。

D: PREPARE stmt_name 的做用域是當前客戶端鏈接會話可見。

E: 要釋放一個預約義語句的資源,可使用 DEALLOCATE PREPARE 句法。

F: EXECUTE stmt_name 句法中,若是 stmt_name 不存在,將會引起一個錯誤。

G: 若是在終止客戶端鏈接會話時,沒有顯式地調用 DEALLOCATE PREPARE 句法釋放資源,服務器端會本身動釋放它。

H: 在預約義語句中,CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE, 和大部分的 SHOW 句法被支持。

I: PREPARE 語句不能夠用於存儲過程,自定義函數!但從 MySQL 5.0.13 開始,它能夠被用於存儲過程,仍不支持在函數中使用!

*/

 

22. 學習prepare

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

20.時間戳

 
 

-- 將參數內的日期 轉換成時間戳  若是參數爲空取當前時間的時間戳

SELECT UNIX_TIMESTAMP('2016/4/18 5:37:36');

-- 將timestamp 形式整數 轉化爲 date類型

SELECT FROM_UNIXTIME(UNIX_TIMESTAMP())

 

 

 

 

 

 

fsContent  LONGTEXT 

CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci

 

21. 長字符串支持表情符號

 

 

 

 

 

22.存儲過程使用dbForge Studio 進行Debug調試

(1) 爲存儲過程,生成調試信息:右擊要調試的過程--"Debug"--"Compile for Debugging', 操做以下

 

 

(2)爲存儲過程設置斷點:打開存儲過程的代碼, 在你要設置斷點的行上雙擊即可

 

 

 

(3)調試存儲過程,單步執行,並查看每一個變量的值。

右擊存儲過程---"Debug"--"Step Into", 以下圖

 

 

先擇"Stop Into"後,若是你的存儲過程有參數,則爲彈出窗體提示輸入參數值,若是沒有,則不直接運行;

存儲過程會從"begin"開始執行,而後點又上角的"step over"(F10), 單步執行。

 

 

查看變量值:選中變量,點右鍵,選擇"Add Wath", 這個變量就會在"Watches"這個視圖區出現,若是你單步運行到這個變量值,則能夠看見了,這樣就能夠調試,變量值是否正確,有錯誤沒,循環次數等。

 

 

 

 

 

23.條件處理

(1)  DECLARE…HANDLER語句 

DECLARE handler_action HANDLER 

    FOR condition_value [, condition_value] ... 

    statement 

 

handler_action: 

    CONTINUE 

  | EXIT 

  | UNDO 

 

condition_value: 

    mysql_error_code 

  | SQLSTATE [VALUE] sqlstate_value 

  | condition_name 

  | SQLWARNING 

  | NOT FOUND 

  | SQLEXCEPTION 

 

     語法以下

 

 

 

 

 

 

 

 

 

a、condition_value [,condition_value],這個的話說明能夠包括多種狀況(方括弧表示可選的),也就是一個handler能夠定義成針對多種狀況進行相應的操做;另外condition_value能夠包括的值有上面列出來的6種:

   一、mysql_error_code,這個表示MySQL的錯誤代碼,錯誤代碼是一個數字,完成是由mysql本身定義的,這個值能夠參考mysql數據庫錯誤代碼及信息

二、SQLSTATE [VALUE] sqlstate_value,這個同錯誤代碼相似造成一一對應的關係,它是一個5個字符組成的字符串,關鍵的地方是它從ANSI SQL和ODBC這些標準中引用過來的,所以更加標準化,而不像上面的error_code徹底是mysql本身定義給本身用的,這個和第一個相似也能夠參考mysql數據庫錯誤代碼及信息

三、condtion_name,這個是條件名稱,它使用DECLARE...CONDITION語句來定義,這個後面咱們會介紹如何定義本身的condition_name。

 四、SQLWARNING,表示SQLTATE中的字符串以‘01’起始的那些錯誤,好比Error: 1311 SQLSTATE:01000 (ER_SP_UNINIT_VAR)

 五、NOT FOUND,表示SQLTATE中的字符串以‘02’起始的那些錯誤,好比Error: 1329 SQLSTATE: 02000(ER_SP_FETCH_NO_DATA),其實這個錯誤就是用在咱們介紹遊標的那個問題所出現的狀況,也就是沒有fetch到記錄,也就是咱們遊標到記錄的尾巴了的狀況。

   六、SQLEXCEPTION,表示SQLSTATE中的字符串不是以'00'、'01'、'02' 起始的那些錯誤,這裏'00'起始的SQLSTATE其實表示的是成功執行而不是錯誤,另外兩個就是上面的4和5的兩種狀況。

上面的6種狀況其實能夠分爲兩類,一類就是比較明確的處理,就是對指定的錯誤狀況進行處理,包括一、二、3這三種方式;另外一類是對對應類型的錯誤的處理,就是對某一羣錯誤的處理,包括四、五、6這三種方式。這個是介紹了condition_value。另外還要注意的一個內容是MySQL在默認狀況下(也就是咱們沒有定義處理錯誤的方法-handler)本身的錯誤處理機制:一、對於SQLWARNING和NOT FOUND的處理方法就是無視錯誤繼續執行,因此在遊標的例子裏面若是咱們沒有對repeat的條件判斷的那個值作個no_more_products=1的handler來處理,那麼循環就會一直下去。二、對於SQLEXCEPTION的話,其默認的處理方法是在出現錯誤的地方就終止掉了。

      b、statement,這個比較簡單就是當出現某種條件/錯誤時,咱們要執行的語句,能夠是簡單的如 SET  var = value這樣的簡單的語句,也能夠是複雜的多行的語句,多行的話可使用BEGIN  .....  END這裏把語句包括在裏面(這個比如delphi裏面的狀況,注意到咱們的存儲過程也是多行的,因此也要BEGIN .... END)。

      c、handler_action,這個表示當執行完上面的statement後,但願執行怎樣的動做,這裏包括CONTINUE、EXIT、UNDO,表示繼續、退出、撤銷(暫時不支持)。這邊就是兩種動做,其實這兩種動做在上面也說過了,CONTINUE就是一個是SQLWARNING和NOT FOUND的默認處理方法,而EXIT就是SQLEXCEPTION的默認處理方法。

來看個簡單的例子,這裏建立一個對SQLSTATE的代碼爲'23000'的錯誤(重複的主鍵)進行處理的HANDLER,每次發生時咱們對變量@x進行增長1:

 

 

 

 

 
 

SET @x = 0;

DROP PROCEDURE IF EXISTS ConditionProc

CREATE PROCEDURE ConditionProc() 

BEGIN 

  DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x = @x+1

  INSERT INTO products values(1,default,default,default,default,default); 

  INSERT INTO products values(1,default,default,default,default,default); 

  SELECT @x; 

END

 

 

 

 

 

 

 

 

 

 

 

 

經過結果咱們知道出現了兩次插入的記錄同原有的記錄出現主鍵重複的狀況。固然這個是由下面這個代碼觸發的。

INSERT INTO products values(1,default,default,default,default,default);

(2) DECLARE...CONDITION語句

DECLARE duplicate_key CONDITION FOR SQLSTATE '23000'; 

DECLARE CONTINUE HANDLER FOR duplicate_key 

  BEGIN 

    -- body of handler 

  END; 

 

這個語句實際上是爲了讓咱們的錯誤條件更加的清晰明瞭化的,對於上面的狀況,像SQLSTATE '23000'這種表示是一種很不直觀的方法,要經過相應的文檔去對應,閱讀起來比較不方便。而DECLARE....CONDITION能夠對條件定義相對應的名稱,看個例子就清楚了:

 

 

 

 

固然在上面的例子咱們沒有用到BEGIN....END,咱們只有一行SET @x=@x+1;這裏咱們用duplicate_key這個條件名稱來對應到SQLSTATE '23000'上面,這樣查看起來更加的直觀。這你duplicate_key就是咱們上面介紹DECLARE....HANDLER時候的那個condition_name。

 

24.INSERT IGNORE INTO 與 INSERT INTO

INSERT IGNORE INTO與INSERT INTO的區別就是INSERT IGNORE INTO會忽略數據庫中已經存在 的數據,若是數據庫沒有數據,就插入新的數據,若是有數據的話就跳過這條數據。這樣就能夠保留數據庫中已經存在數據,達到在間隙中插入數據的目的。

25.關於MySQL存儲引擎--MyISAM與InnoDB區別

MyISAM 和InnoDB 講解

  InnoDB和MyISAM是許多人在使用MySQL時最經常使用的兩個表類型,這兩個表類型各有優劣,視具體應用而定。基本的差異爲:MyISAM類型不支持事務處理等高級處理,而InnoDB類型支持。MyISAM類型的表強調的是性能,其執行數度比InnoDB類型更快,可是不提供事務支持,而InnoDB提供事務支持以及外部鍵等高級數據庫功能。

  如下是一些細節和具體實現的差異:

  ◆1.InnoDB不支持FULLTEXT類型的索引。

  ◆2.InnoDB 中不保存表的具體行數,也就是說,執行select count(*) from table時,InnoDB要掃描一遍整個表來計算有多少行,可是MyISAM只要簡單的讀出保存好的行數便可。注意的是,當count(*)語句包含 where條件時,兩種表的操做是同樣的。

  ◆3.對於AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,可是在MyISAM表中,能夠和其餘字段一塊兒創建聯合索引。

  ◆4.DELETE FROM table時,InnoDB不會從新創建表,而是一行一行的刪除。

  ◆5.LOAD TABLE FROM MASTER操做對InnoDB是不起做用的,解決方法是首先把InnoDB表改爲MyISAM表,導入數據後再改爲InnoDB表,可是對於使用的額外的InnoDB特性(例如外鍵)的表不適用。

  另外,InnoDB表的行鎖也不是絕對的,假如在執行一個SQL語句時MySQL不能肯定要掃描的範圍,InnoDB表一樣會鎖全表,例如update table set num=1 where name like 「%aaa%」

  兩種類型最主要的差異就是Innodb 支持事務處理與外鍵和行級鎖。而MyISAM不支持.因此MyISAM每每就容易被人認爲只適合在小項目中使用。

  做爲使用MySQL的用戶角度出發,Innodb和MyISAM都是比較喜歡的,若是數據庫平臺要達到需求:99.9%的穩定性,方便的擴展性和高可用性來講的話,MyISAM絕對是首選。

  緣由以下:

  一、平臺上承載的大部分項目是讀多寫少的項目,而MyISAM的讀性能是比Innodb強很多的。

  二、MyISAM的索引和數據是分開的,而且索引是有壓縮的,內存使用率就對應提升了很多。能加載更多索引,而Innodb是索引和數據是緊密捆綁的,沒有使用壓縮從而會形成Innodb比MyISAM體積龐大不小。

  三、常常隔1,2個月就會發生應用開發人員不當心update一個表where寫的範圍不對,致使這個表無法正經常使用了,這個時候MyISAM的優越性就體現出來了,隨便從當天拷貝的壓縮包取出對應表的文件,隨便放到一個數據庫目錄下,而後dump成sql再導回到主庫,並把對應的binlog補上。若是是Innodb,恐怕不可能有這麼快速度,別和我說讓Innodb按期用導出xxx.sql機制備份,由於最小的一個數據庫實例的數據量基本都是幾十G大小。

  四、從接觸的應用邏輯來講,select count(*) 和order by 是最頻繁的,大概能佔了整個sql總語句的60%以上的操做,而這種操做Innodb其實也是會鎖表的,不少人覺得Innodb是行級鎖,那個只是where對它主鍵是有效,非主鍵的都會鎖全表的。

  五、還有就是常常有不少應用部門須要我給他們按期某些表的數據,MyISAM的話很方便,只要發給他們對應那表的frm.MYD,MYI的文件,讓他們本身在對應版本的數據庫啓動就行,而Innodb就須要導出xxx.sql了,由於光給別人文件,受字典數據文件的影響,對方是沒法使用的。

  六、若是和MyISAM比insert寫操做的話,Innodb還達不到MyISAM的寫性能,若是是針對基於索引的update操做,雖然MyISAM可能會遜色Innodb,可是那麼高併發的寫,從庫可否追的上也是一個問題,還不如經過多實例分庫分表架構來解決。

  七、若是是用MyISAM的話,merge引擎能夠大大加快應用部門的開發速度,他們只要對這個merge表作一些select count(*)操做,很是適合大項目總量約幾億的rows某一類型(如日誌,調查統計)的業務表。

  固然Innodb也不是絕對不用,用事務的項目就用Innodb的。另外,可能有人會說你MyISAM沒法抗太多寫操做,可是能夠經過架構來彌補。

 

 

 

 

 

 

26.存儲過程調試

可使用mysql自帶的日誌表 mysql.general_log的記錄 查詢出存儲過程的調用語句,執行。可使用debug也可以使用select語句進行跟蹤調試

 
 

-- 查看mysql的整個調用信息

SELECT * FROM mysql.general_log a WHERE a.argument LIKE 'CALL%' ORDER BY event_time desc LIMIT 10;

 

 

 

 

 

 

 

27.存儲過程實現遞歸

 
 

DROP PROCEDURE IF EXISTS css.testRecursion;

CREATE PROCEDURE css.testRecursion(INOUT i INT,INOUT result INT)

lblTop:BEGIN

/*

  存儲過程實現遞歸

*/

  IF i <= 0  THEN

    LEAVE lblTop;

  END IF;

  IF result = 0 OR result = NULL THEN

    SET result = 0;

  END IF;

  # 遞歸調用不能嵌套超過10層

  IF i > 11 THEN

    LEAVE lblTop;

  END IF;

  IF i >= 1 THEN

    SET result = result + (i);

    SET i = i - 1;

    CALL testRecursion( i,result);

  ELSE

   LEAVE lblTop;

  END IF;

END

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

28.PREPARE 預備語句

-- 定義預備語句

PREPARE stmt_name FROM preparable_stmt;

-- 執行預備語句

EXECUTE stmt_name [USING @var_name [, @var_name] ...];

-- 解除預備語句

{DEALLOCATE | DROP} PREPARE stmt_name;

 

(1)語法

 

 

 

 

(2) 例子

PREPARE myPre FROM "SELECT * FROM zhucwTest0421 LIMIT ?,?";

-- 佔位符只能由用戶變量取代

SET @a = 2;

SET @b = 4;

EXECUTE myPre USING @a,@b;

DEALLOCATE myPre;

 

 

 

 

 

 

 

 

(3)使用PREPARE 須要注意

① PREPARE stmt_name FROM preparable_stmt;預約義一個語句,並將它賦給 stmt_name ,tmt_name 是不區分大小寫的。
②  即便 preparable_stmt 語句中的 ? 所表明的是一個字符串,你也不須要將 ? 用引號包含起來。 
③  若是新的 PREPARE 語句使用了一個已存在的 stmt_name ,那麼原有的將被當即釋放! 即便這個新的 PREPARE 語句由於錯誤而不能被正確執行。
④ PREPARE stmt_name 的做用域是當前客戶端鏈接會話可見。 
⑤ 要釋放一個預約義語句的資源,可使用 DEALLOCATE PREPARE 句法。 
⑥ EXECUTE stmt_name 句法中,若是 stmt_name 不存在,將會引起一個錯誤。 
⑦ 若是在終止客戶端鏈接會話時,沒有顯式地調用 DEALLOCATE PREPARE 句法釋放資源,服務器端會本身動釋放它。 
⑧在預約義語句中,CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE, 和大部分的 SHOW 句法被支持。
⑨ PREPARE 語句不能夠用於存儲過程,自定義函數!但從 MySQL 5.0.13 開始,它能夠被用於存儲過程,仍不支持在函數中使用! 

⑩ PREPARE 語句裏的佔位符參數值只能有用戶變量提供,USING子句必須準確地指明用戶變量,用戶變量的數目與語句中的參數製造符的數量同樣多。

DROP PROCEDURE IF EXISTS css.testCycle;

CREATE PROCEDURE testCycle(IN i INT,IN cycle VARCHAR(50))

BEGIN

 

  DECLARE sContent1 VARCHAR(50) DEFAULT 'content1';

  DECLARE sContent2 VARCHAR(50) DEFAULT 'content2';

  -- 預備一個語句

  PREPARE myPre FROM "INSERT INTO css.zhucwTest0421(content1,content2) VALUES (CONCAT(?,?),CONCAT(?,?))";

 

  # CASE 語句

  CASE WHEN cycle = "WHILE"

             THEN

                # WHILE 循環

                WHILE i > 0 DO

                  SET sContent1 = "WHILE1";

                  SET sContent2 = "WHILE2";

                  SET @pContent1 = sContent1;

                  SET @pContent2 = sContent2;

                  SET @pI = i;

                  -- 執行預備的語句

                  EXECUTE myPre USING @pContent1,@pI,@pContent2,@pI;

                  SET i = i - 1;

                END WHILE;

         WHEN  cycle = "REPEAT"

             THEN

                 # REPEAT循環

                 lblRepeat:REPEAT

                    IF i = 0 THEN

                      LEAVE lblRepeat;

                    END IF;

                    SET sContent1 = "REPEAT1";

                    SET sContent2 = "REPEAT2";

                    SET @pContent1 = sContent1;

                    SET @pContent2 = sContent2;

                    SET @pI = i;

                    EXECUTE myPre USING @pContent1,@pI,@pContent2,@pI;

                    SET i = i - 1;

                    UNTIL i = 0

                  END REPEAT;          

 

29.CASE…WHEN…ELSE…END CASE與各項循環結合例子

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

         WHEN  cycle = "LOOP"

             THEN

                 # LOOP循環    

                 lblLoop:LOOP

                    IF i = 0 THEN

                      LEAVE lblLoop;

                    END IF;

                    SET sContent1 = "LOOP1";

                    SET sContent2 = "LOOP2";;

                    SET @pContent1 = sContent1;

                    SET @pContent2 = sContent2;

                    SET @pI = i;

                    EXECUTE myPre USING @pContent1,@pI,@pContent2,@pI;

                    SET i = i - 1;

                  END LOOP;

         WHEN cycle = "ITERATE"

             THEN

                 # ITERATE

                 lblLoop2:LOOP

                    SET sContent1 = "ITERATE1";

                    SET sContent2 = "ITERATE2";

                    SET @pContent1 = sContent1;

                    SET @pContent2 = sContent2;

                    SET @pI = i;

                    EXECUTE myPre USING @pContent1,@pI,@pContent2,@pI;

                    SET i = i - 1;

                    IF i > 0 THEN

                      ITERATE lblLoop2;

                    ELSE

                      LEAVE lblLoop2;

                    END IF;

                  END LOOP;   

         ELSE

                 # OTHER

                 lblRepeat3 : REPEAT

                     SET sContent1 = "Other1";

                     SET sContent2 = "Other2";

                     SET @pContent1 = sContent1;

                     SET @pContent2 = sContent2;

                     SET @pI = i;

                     EXECUTE mypre USING @pContent1,@pContent2,@pI;

                     SET i = i - 1;

                  UNTIL i <= 0

                  END REPEAT;             

  END CASE;

  DEALLOCATE PREPARE myPre;

END;

 
相關文章
相關標籤/搜索