mysql存儲過程語法與實例


大綱:

  1. 創建、刪除、調用。
  2. 聲明變量、變量賦值、存儲過程的入參
  3. 聲明游標
  4. 聲明異常處理器
  5. 判斷
  6. 循環
  7. 使用心得
  8. mybatis調用存儲過程

 

一、創建、刪除、調用

  • 創建
    DELIMITER $$ #修改分隔符
    CREATE PROCEDURE test(IN pname VARCHAR(50)) #括號里是入參。
      BEGIN
        select pname; #存儲過程中的語句用;結尾
      END$$ #存儲過程本身用修改后的分隔符$$結尾
    DELIMITER ; ##還原分隔符

    begin、end之間是存儲的執行的代碼塊。

   tips:mysql不支持匿名塊(沒有create procedure,直接寫begin、end之間的內容),因此msql的代碼塊只能放在存儲過程,自定義函數,觸發器中。

  • 刪除
    DROP PROCEDURE IF EXISTS test; #存儲過程

    和表一樣建立前確保數據庫中沒有同名存儲過程。

  • 調用
    CALL test('xx');

    調用用call命令、這里參數傳一個字符串進去、調用后顯示xx。

 

二、聲明變量、變量賦值、存儲過程的入參

  • declare聲明變量
  • set是直接賦值(可以用 '=' 號賦值,也可以用 ':=' 賦值,本文例子中都是用 '=' 賦值的。但之后的學習中發現用這種 ':=' 方式賦值更規范一些。)
  • select是將查詢的結果進行賦值
    DROP PROCEDURE IF EXISTS test;
    DELIMITER $$
    CREATE PROCEDURE test(IN pname VARCHAR(50))
      BEGIN
        DECLARE prefix VARCHAR(20); #聲明變量
        set prefix = 'nihao:'; #select 'nihenhao:' into prefix; 賦值
        select concat(prefix,pname); #concat函數:拼接2個字符串
      END$$
    DELIMITER ;
    CALL test('xx');:賦值方式有2種、根據需求選擇。
  •  創建存儲過程的時候已經提到了,存儲過程可以有入參IN,也可以有出參OUT,還可以有出入參INOUT。IN類型只能作為傳入參數使用,OUT只能作為傳出參數使用,只有INOUT既可以傳入存儲過程又能傳出來。
    drop PROCEDURE test;
    DELIMITER $$
    CREATE PROCEDURE test( IN people VARCHAR(8), OUT name VARCHAR(8),INOUT age INT )
    BEGIN
        IF people = 'man'
        THEN SET name := 'xiaoming';
          SET age :=age+1;
        ELSE SET name := 'xiaohong';
          SET age :=age+10;
        END IF;
      END $$
    
    set @people = 'man'; #@var_name這樣的寫法是聲明一個用戶變量,只有在本次連接的客戶端中有效。這里聲明了3個變量people、name、age
    set @name = null;
    set @age = 6;
    call test(@people,@name,@age);
    SELECT @people,@name,@age from dual; #結果:man     xiaoming     7

     

三、聲明游標

  • 准備一個測試表
    TRUNCATE names;
    create table names
    (
      name VARCHAR(20),
      age int
    );
    INSERT into names VALUES ('lby',45);
    INSERT into names VALUES ('lala',23);
  • 游標可以理解為是一個帶指針的結果集。
    DROP PROCEDURE IF EXISTS test;
    DELIMITER $$
    CREATE PROCEDURE test()
      BEGIN
        DECLARE name VARCHAR(20);
        DECLARE age int;
        DECLARE temp VARCHAR(50);
        DECLARE c1 CURSOR FOR select * from names; #聲明游標
        OPEN c1; #使用游標前打開游標
        FETCH c1 INTO name,age; #將游標中的第一行依次付給name,age(name=lby,age=45)。tips:游標列數和變量數要相同。
        set temp = CONCAT(name,age);
        FETCH c1 INTO name,age; #第一次fetch后指針下移動,賦值第二行給name,age(name=lala,age=23)。
        CLOSE c1; #使用游標后關閉游標
        set temp = CONCAT(temp,CONCAT(name,age));
        SELECT temp from dual; #lby45lala23
      END$$
    DELIMITER ;
    CALL test();

 

四、聲明異常處理器

  • 當sql執行時報錯時會報出相應的sqlstate,根據不同的sqlstate我們可以給出不同的處理。--附一個sqlstate的詳解:blog.csdn.net/u014653854/article/details/78986780
  • 處理器有2種:exit、continue。
    TRUNCATE names; #清空names表使fetch報錯SQLSTATE'02000'
    DROP PROCEDURE IF EXISTS test;
    DELIMITER $$
    CREATE PROCEDURE test()
      BEGIN
        declare age int default 0 ;
        declare name VARCHAR(20) default 0 ;
        declare flag int default 0;
        DECLARE c1 CURSOR FOR select * from names;
        declare CONTINUE HANDLER FOR SQLSTATE '02000' SET flag = 111;  # continue handler 檢測報錯為02000的時候 將flag設為111,存儲過程繼續執行,如果換為exit handler在行為完處理語句set flag=111后直接退出存儲過程。
        OPEN c1;
        FETCH c1 into name,age; #當執行這句時會報錯sqlstate:02000 ,continue handler觸發set flag= 111,繼續執行后面的代碼。
        CLOSE c1;
        select flag; #111
      END$$
    DELIMITER ;
    CALL ifpay_ccpay.test();

 

五、判斷

  • if判斷
    DROP PROCEDURE IF EXISTS test;
    DELIMITER $$
    CREATE PROCEDURE test(in age int)
      BEGIN
        declare flag VARCHAR(20);
        IF age = 1 THEN SET flag = '';
        ELSEIF age = 2 THEN SET flag = '';
        ELSE SET flag = 'I DONT KNOW';
        END IF; #結束標志
        select flag; #二
      END$$
    DELIMITER ;
    CALL ifpay_ccpay.test(2);

 

六、循環

循環有三種

  • while循環
    DROP PROCEDURE IF EXISTS test;
    DELIMITER $$
    CREATE PROCEDURE test()
      BEGIN
        DECLARE age int DEFAULT 0;
        mywhile:
        WHILE age < 5 #條件,
        DO
          set age = age+1; #do與endwhile之間是循環內容
        END WHILE ;
        SELECT age; #5
      END$$
    DELIMITER ;
    CALL test();

     

  • repeat循環
    DROP PROCEDURE IF EXISTS test;
    DELIMITER $$
    CREATE PROCEDURE test()
      BEGIN
        DECLARE age int DEFAULT 0;
        mywhile:
        repeat
         set age = age+1; #循環體
        UNTIL age>3 END REPEAT ; #條件
        SELECT age; #4
      END$$
    DELIMITER ;
    CALL test();

     

  • loop循環
    DROP PROCEDURE IF EXISTS test;
    DELIMITER $$
    CREATE PROCEDURE test()
      myproc: #存儲過程的label
      BEGIN
        DECLARE age int DEFAULT 0;
        DECLARE count int DEFAULT 10;
        myloop: #loop的label
        LOOP
          set age = age +1;
          IF age < 5 then
            ITERATE myloop; #忽略后面代碼繼續執行。(continue)
          END IF;
          set count = count - 1; 
          SELECT 'haha'; 
          LEAVE myloop; #離開循環。(break) leave也可直接用於存儲過程本身myproc,如果這里換成myproc,則顯示haha
        END LOOP;
        SELECT age,count; #5    9
      END$$
    DELIMITER ;
    CALL test();

   代碼中有3個概念:label、iterate、leave

   label:名稱標簽,while、repeat、loop循環或者 存儲過程本身begin關鍵字前面都可以加一個名稱標簽。  

   iterate:用於循環、繼續當前循環,相當於java循環中的continue。

   leave:1.用於循環、離開當前循環,相當於java循環中的break。

        2.也可用於存過過程本身,直接離開存過過程。

 

循環小結:1.while repeat區別在於:while 先判斷循環條件再循環,repeat 線循環后判斷。

     2.loop沒有結束條件,需要手動退出。

     3.iterate、leave也可以用於while、repeat。

 

七、使用心得

  1. 存儲過程中慎用delete語句。
  2. 存儲過程適合一些有規律的數據操作,比如根據一些業務規則初始化一些數據。
  3. 盡量不要用它代替簡單的業務sql,因為存儲過程的維護、遷移、易讀性都不如直接寫在代碼中好。

 

八、mybatis調用存儲過程

調用方式參考我另一篇文章:mybatis調用存儲過程


免責聲明!

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



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