MySql存儲過程總結


 今天需要用到MYSQL,研究了下,把項目的需要的存儲過程寫了一部分,寫一下工作總結。這里沒有給出數據庫結構,不討論SQL語句的細節,主要探討存儲過程語法,適合有基礎的人。

 

快速入門

理解:

   迄今為止,我們學過的大多數SQL語句都是針對一個或多個表的單條語句。但是並不是所有的操作都是可以用一條語句來完成的,經常有一些操作是需要多條語句配合才能完成我們引入的存儲過程(Stored Procedure)是一組為了完成特定功能的SQL語句集,經編譯后存儲在數據庫中,用戶通過指定存儲過程的名字並給定參數(如果該存儲過程帶有參數)來調用執行它。
  簡單來說,存儲過程就是為以后使用而保存的一條或多條SQL語句。可將其視為增強版的批處理文件。   

使用存儲過程的好處
  ☐ 通過把處理封裝在一個易用的單元中,可以簡化復雜的操作。
  ☐ 不需要反復建立一系列的處理步驟,因而保證了數據的一致性。
  ☐ 簡化了對變動的管理,這一點的延伸就是安全性。
  ☐ 存儲過程通常以編譯過的形式存儲,所以DBMS處理命令所需的工作量少,提高了性能。

創建:

創建語句:

  

一般形式:

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

說明:
  DELIMITER $$ DELIMITER; 用來定義分隔符,因為MySQL默認以";"為分隔符,如果我們沒有聲明分割符,那么編譯器會把存儲過程當成SQL語句進行處理,則存儲過程的編譯過程會報錯,所以要事先用DELIMITER關鍵字申明當前段分隔符,這樣MySQL才會將";"當做存儲過程中的代碼,不會執行這些代碼,用完了之后要把分隔符還原。

調用:

示例:
  

說明:

  CALL Avg_Price(); 執行剛創建的存儲過程並顯示返回的結果。因為存儲過程實際上是一種函數,所以存儲過程名后需要有 () 符號(即使不傳遞參數也需要)

刪除:

  


說明:

  請注意只給出了存儲過程名,並沒有書寫()。

使用參數

說明  

  在上面我們簡單地顯示SELECT語句的結果,一般存儲過程並不顯示結果,而是把結果返回給你指定的變量
  現在我們需求如下

    計算商品的最低,最高和平均價格,並保存到三個變量中。

創建存儲過程

  

調用此存儲過程

  

使用IN參數傳入條件

  創建存儲過程:

  

  調用存儲過程:

  

更加智能的存儲過程

說明:

  迄今為止使用的所有存儲過程基本上都是封裝MySQL簡單的 SELECT語句。雖然它們全都是有效的存儲過程例子,但它們所能完成的工作你直接用這些被封裝的語句就能完成(如果說它們還能帶來更多的東西,那就是使事情更復雜)。只有在存儲過程內包含業務規則和智能處理時,它們的威力才真正顯現出來,來使我們的語句執行更加可靠和智能,比如我們可以聲明局部變量、添加內部注釋、使用循環或判斷語句等等

實例:

  

常用控制語句及示例

(1). 條件語句

. if-then -else語句

    mysql > DELIMITER //  
    mysql > 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;  
         -> //  
    mysql > DELIMITER ;  


. case語句: 

     mysql > DELIMITER //  
    mysql > 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;  
         -> //  
    mysql > DELIMITER ;

(2). 循環語句

. while ···· end while

    mysql > DELIMITER //  
    mysql > 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;  
         -> //  
    mysql > DELIMITER ; 

. repeat···· end repeat

它在執行操作后檢查結果,而while則是執行前進行檢查。

     mysql > DELIMITER //  
    mysql > 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;  
         -> //  
    mysql > DELIMITER ; 


. loop ·····end loop:

loop循環不需要初始條件,這點和while 循環相似,同時和repeat循環一樣不需要結束條件, leave語句的意義是離開循環。

     mysql > DELIMITER //  
    mysql > 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;  
         -> //  
    mysql > DELIMITER ;  
 

. LABLES 標號:

標號可以用在begin repeat while 或者loop 語句前,語句標號只能在合法的語句前面使用。可以跳出循環,使運行指令達到復合語句的最后一步。

 

(3). ITERATE迭代

. ITERATE:

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

         mysql > DELIMITER //  
        mysql > 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;  
             -> //  
        mysql > DELIMITER ;
 
#查詢文章回復
-- ----------------------------
-- Procedure structure for `sp_select_reply_article`
-- ----------------------------
DROP PROCEDURE IF EXISTS `sp_select_reply_article`;
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_select_reply_article`(IN `ra_id` int,IN `pagefrom` int,IN `pagesize` int)
BEGIN
         #Routine body goes here...
         SET @ra_id = ra_id;
         SET @pagefrom = pagefrom;
         SET @pagesize = pagesize;
         SET @ssra = CONCAT('SELECT * FROM gk_article WHERE id = ? LIMIT ?,?');
         PREPARE sqlquery FROM @ssra;
         EXECUTE sqlquery USING @ra_id,@pagefrom,@pagesize;
END
;;
DELIMITER ;

 

#技術點1:MySql5.1不支持LIMIT參數(MySql5.5就支持了),如果編寫存儲過程時使用LIMIT做變量,那是需要用動態SQL來構建的,而這樣做性能肯定沒有靜態SQL好。主要代碼如下:

         SET @ssra = CONCAT('SELECT * FROM gk_article WHERE id = ? LIMIT ?,?');

         PREPARE sqlquery FROM @ssra;

         EXECUTE sqlquery USING @ra_id,@pagefrom,@pagesize;

 

#技術點2:如果同時需要返回受影響行數需要在語句后面添加語句:ROW_COUNT()函數,兩條語句之間需要“;”分隔。

 

 
#更新數據
-- ----------------------------
-- Procedure structure for `sp_update_permission`
-- ----------------------------
DROP PROCEDURE IF EXISTS `sp_update_permission`;
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_update_permission`(IN `puser_uid` varchar(20),IN `plevel` int,IN `ppower` int)
BEGIN
         #Routine body goes here...
        
         SET @puser_uid = puser_uid;
         SET @plevel = plevel;
         SET @ppower = ppower;
         UPDATE gk_permission SET `level` = @plevel, power = @ppower WHERE user_uid = CONVERT(@puser_uid USING utf8) COLLATE utf8_unicode_ci;
END
;;
DELIMITER ;
 

 

#技術點3:MySQL進行字符串比較時發生錯誤(Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and (utf8_general_ci,IMPLICIT) for operation '='),解決方法:將比較等式一邊進行字符串轉換,如改為“CONVERT(b.fullCode USING utf8) COLLATE utf8_unicode_ci”,主要代碼如下:

         UPDATE gk_permission SET `level` = @plevel, power = @ppower WHERE user_uid = CONVERT(@puser_uid USING utf8) COLLATE utf8_unicode_ci;

 

 
#插入數據
-- ----------------------------
-- Procedure structure for `sp_insert_user`
-- ----------------------------
DROP PROCEDURE IF EXISTS `sp_insert_user`;
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_insert_user`(IN `uid` varchar(20),IN `upw` varchar(32),IN `name` varchar(20),IN `sex` int,IN `phone` varchar(20),IN `u_id` int,IN `s_id` int,IN `j_id` int)
BEGIN
         #Routine body goes here...
         SET @uid = uid;
         SET @upw = upw;
         SET @uname = uname;
         SET @sex = sex;
         SET @phone = phone;
         #由於外鍵約束,所以添加的外鍵字段需要在對應外鍵所在表有相應數據
         SET @u_id = u_id;
         SET @s_id = s_id;
         SET @j_id = j_id;
         SET @verifytime = DATE('0000-00-00');
         INSERT INTO gk_user(uid,upw,uname,sex,phone,u_id,s_id,j_id,verifytime) 
       VALUES(@uid,@upw,@uname,@sex,@phone,@u_id,@s_id,@j_id,@verifytime); #查詢結果會自動返回受影響行數 END ;; DELIMITER ;
 

 

 #根據ID刪除數據
-- ----------------------------
-- Procedure structure for `sp_delete_exchange_by_id`
-- ----------------------------
DROP PROCEDURE IF EXISTS `sp_delete_exchange_by_id`;
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_delete_exchange_by_id`(IN `eid` int)
BEGIN
         #Routine body goes here...
         SET @eid = eid;
         DELETE FROM gk_exchange WHERE id = @eid;
END
;;
DELIMITER ; 

 

 #通過賬號查詢用戶或者管理員
-- ----------------------------
-- Procedure structure for `sp_select_user_by_uid`
-- ----------------------------
DROP PROCEDURE IF EXISTS `sp_select_user_by_uid`;
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_select_user_by_uid`(IN `uid` varchar(20),IN `getAdmin` int)
BEGIN
         #Routine body goes here...
         SET @uid = uid;
         #SET @getadmin = getAdmin;
         #查詢管理員
         IF (getAdmin = 1) THEN
                   SELECT us.*, un.`name`, se.`name`, jo.`name`, pe.`level`, pe.power FROM gk_user AS us, gk_unit AS un, gk_section AS se, gk_jobtitle AS jo, gk_permission AS pe WHERE us.u_id = un.id AND us.s_id = se.id AND us.j_id = jo.id AND us.uid = pe.user_uid AND us.uid = CONVERT(@uid USING utf8) COLLATE utf8_unicode_ci;
         END IF;
         #查詢用戶
         IF (getAdmin = 0) THEN
                   SELECT us.*, un.`name`, se.`name`, jo.`name` FROM gk_user AS us, gk_unit AS un, gk_section AS se, gk_jobtitle AS jo WHERE us.u_id = un.id AND us.s_id = se.id AND us.j_id = jo.id AND us.uid = CONVERT(@uid USING utf8) COLLATE utf8_unicode_ci;
         END IF;
END
;;
DELIMITER ;  

#技術點4:這個存數過程需要用到控制語句(if else elseif while loop repeat leave iterate)。

         IF (getAdmin = 1) THEN

                   #語句…

         END IF; 

#技術點5:在傳入參數不匹配的情況下報錯(Column count doesn't match value count at row 1),這個就是細心問題了,詳細檢查參數吧。

 

#技術點6:獲取當前時間的函數:NOW()

 

#技術點7:“`”這個符號是反單引號,兩個反單引號夾起來的會被當做變量,一般是在定義字段時遇到關鍵字沖突的時候會用到。

 

 

 

 


免責聲明!

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



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