• MySQL存储过程详解


    一、使用场景
    1.执行时简单:名字+参数
    2.存储过程中可以有一个、多个sql语句。
    问:为啥要用存储过程?
    答:
    ①将重复性很高的一些操作,封装到一个存储过程中。简化了对这些SQL的调用。
    ②批量处理sql+循环
    ③统一接口
    注意:mysql中,存储功能相对较弱。使用较少。

    二、基本建立语法
    例1:

    DELIMITER $$
    CREATE PROCEDURE delete_matches(IN p playerno INTEGER)
        BEGIN
            DELETE FROM MATCHES
                WHERE playerno=p_playerno;
        END$$
    DELIMITER;
    call delete_matches(6);

    例2:

    delimiter $$
    CREATE PROCEDURE dorepeat(p1 INT)
    BEGIN
      SET @x = 0;  --》用set赋值, repeat循环
      REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
    END$$
    delimiter ;
    CALL dorepeat(1000);
    SELECT @x;
    执行后:@x的值为1001

    @变量名字的作用:

    • ①存储过程中定义,存储过程中进行处理,加减乘除。
    • ②存储过程外面可以访问这个@变量,这个变量保存了存储过程中对这个变量处理后的值。

    @x:用户变量

    • 存储过程外面可以访问,一直被保存。
    • 直接使用set @x=0;就可以生成这么一个变量,不需要数据类型。

    三、存储过程参数
    三类:in(输入参数)、out(输出参数)、inout(输入和输出参数)
    存储过程需要是活的–》输入不同的参数,执行不同的操作,处理不同的行等等。

    IN参数

    DELIMITER $$
    CREATE PROCEDURE delete matches(IN p playerno INTEGER)
        BEGIN
            DELETE FROM MATCHES
                WHERE playerno=p_playerno;
        END$$
    DELIMITER;
    call delete_matches(6);

    IN参数可以是:数值100、赋值了的变量 set @a=100;

    OUT参数

    delimiter $$
    CREATE PROCEDURE simpleproc (OUT param1 INT)
        BEGIN
          SELECT COUNT(*) INTO param1 FROM PLAYERS;
        END$$
    delimiter ;
    CALL simpleproc(@a);
    SELECT @a;

    OUT参数:变量就可以,可以没有赋值。 @a

    INOUT参数

    delimiter $$
    CREATE PROCEDURE simpleproc1(INOUT param1 INT)
    BEGIN
      SELECT COUNT(*) INTO param1 FROM PLAYERS where PLAYERNO<=param1;
    END$$
    delimiter ;
    set @a=10;
    CALL simpleproc1(@a);    --》调用存储过程时,只要引用变量就行!
    SELECT @a;
    INOUT参数:只能是赋了值得变量。 set @a=100

    一个存储过程如果想有返回值:

    • 1.out参数
    • 2.inout参数
    • 3.在存储过程内部定义用户变量

      @变量名字
      建议:返回值使用out参数;输入值使用in参数。

    四、begin…end语法
    为什么需要begin…end?
    答:
    ①因为begin…end语句之间的n条语句属于一条语句,一个整体。
    ②成对出现。

    BEGIN
         sql语句
    END$$

    五、变量
    1.用户变量@

    • 随处可定义,随处可使用;
    • 不定义可直接使用;
    • 随处可见;
    • 内部定义,外部可见。

    2.局部变量,只有名字,没有@符号

    • 先定义,再使用;
    • 只在存储过程内部可见;只能定义在begin后面!

    注意:在存储过程内部,使用局部变量,不要使用用户变量。

    用户变量和局部变量的区别:

    • ①局部变量前面没有@符号
    • ②当begin…end块处理完后,局部变量就消失了,而用户变量存在于整个会话之中。

    定义局部变量:
    DECLARE 变量名字 类型 [default] –》而且declare必须紧接着begin!
    例:

    DECLARE var_name [, var_name] ... type [DEFAULT value]
    delimiter $$
    CREATE PROCEDURE sp1 (x VARCHAR(10))
    BEGIN
      DECLARE newname VARCHAR(10);
      DECLARE xid INT;
      SELECT xname, id INTO newname, xid
        FROM table1 WHERE xname = x;
      SELECT newname;
    END$$
    delimiter ;
    call sp1('a');

    初始化局部变量:

    delimiter $$
    CREATE  PROCEDURE test1(OUT num1 INTEGER)   
        BEGIN     
          DECLARE num2 INTEGER DEFAULT (SELECT count(*) FROM PLAYERS);
          SET num1 = num2;
        END$$
    delimiter ;

    begin…end的作用域:

    • 外层看不到内层;
    • 内层可以看到外层;
    • 平行互相看不见。

    SET
    可以给用户变量和局部变量赋值
    用户变量内外都可以使用
    局部变量,只有begin end之间可以使用,而且需要declare定义

    六、IF…ELSE

    DELIMITER $$    --》定义$$为分界符
    CREATE  PROCEDURE difference(
      IN p1 INTEGER,        --》整数
      IN p2 INTEGER,  
      OUT p3 INTEGER)   
     BEGIN     
       IF p1 > p2 THEN
          SET p3 = 1;
       ELSEIF p1= p2 THEN
         SET p3 = 2;
       ELSE
         SET p3 = 3;
       END IF;        
     END$$
    DELIMITER ;
    mysql> call difference(1,10,@p);
        Query OK, 0 rows affected (0.00 sec)
    mysql> select @p;
    +------+
    | @p   |
    +------+
    |    3 |
    +------+
    1 row in set (0.01 sec)

    七、函数
    1.返回值
    两个return:一个标志返回什么类型;一个实际的返回值。
    2.调用函数:函数需要出现在=的右边

    例子:

    DELIMITER $$
    CREATE FUNCTION SimpleCompare(n INT, m INT)
      RETURNS VARCHAR(20)
      BEGIN
        DECLARE s VARCHAR(20);
        IF n > m THEN SET s = '>';
        ELSEIF n = m THEN SET s = '=';
        ELSE SET s = '<';
        END IF;
        SET s = CONCAT(n, ' ', s, ' ', m);
        RETURN s;
      END$$
    DELIMITER ;
    mysql> select SimpleCompare(1,2) ;
    +--------------------+
    | SimpleCompare(1,2) |
    +--------------------+
    | 1 < 2              |
    +--------------------+
    1 row in set (0.01 sec)
    mysql> set @a=SimpleCompare(1,2) ;
    Query OK, 0 rows affected (0.01 sec)
    mysql> select @a;
    +-------+
    | @a    |
    +-------+
    | 1 < 2 |
    +-------+
    1 row in set (0.00 sec)

    八、case…end case
    例1:

    DELIMITER $$
    CREATE  PROCEDURE difference1(
      IN p1 INTEGER,
      IN p2 INTEGER,  
      OUT p3 INTEGER)   
     BEGIN 
       CASE    
         WHEN  p1 > p2 THEN
           SET p3 = 1;
         WHEN p1= p2 THEN
           SET p3 = 2;
         ELSE
           SET p3 = 3;
       END CASE;        
     END$$
    DELIMITER ;
    mysql> call difference1(1,100,@a);
    Query OK, 0 rows affected (0.01 sec)
    mysql> select @a;
    +------+
    | @a   |
    +------+
    |    3 |
    +------+
    1 row in set (0.00 sec)

    例2:

    DELIMITER $$
    CREATE PROCEDURE p(x INT)
      BEGIN
        DECLARE v INT DEFAULT 1;
        set v=x;
        CASE v
          WHEN 2 THEN SELECT v;
          WHEN 3 THEN SELECT 0;
          ELSE
            BEGIN
            END;
        END CASE;
      END$$
    DELIMITER ;
    mysql> call p(2);
    +------+
    | v    |
    +------+
    |    2 |
    +------+
    1 row in set (0.00 sec)
    Query OK, 0 rows affected (0.01 sec)
    mysql> call p(3);
    +---+
    | 0 |
    +---+
    | 0 |
    +---+
    1 row in set (0.00 sec)
    Query OK, 0 rows affected (0.00 sec)

    九、while
    例题:

    DELIMITER $$
    CREATE PROCEDURE dowhile(x int)
    BEGIN
      DECLARE v1 INT DEFAULT 5;
        set v1=x;
      WHILE v1 > 0 DO
        select v1;
        SET v1 = v1 - 1;
      END WHILE;
    END$$
    DELIMITER ;
    mysql> call dowhile(10);
    +------+
    | v1   |
    +------+
    |   10 |
    +------+
    1 row in set (0.01 sec)
    +------+
    | v1   |
    +------+
    |    9 |
    +------+
    1 row in set (0.01 sec)
    。。。一直到1

    十、repeat…until
    先执行,再判断。
    例题:

    delimiter //
    CREATE PROCEDURE dorepeat1(p1 INT)
    BEGIN
      SET @x = 0;
      REPEAT
        SET @x = @x + 1;
      UNTIL @x > p1 
      END REPEAT;
    END//
    delimiter ;
    mysql> call dorepeat1(10);
    Query OK, 0 rows affected (0.01 sec)
    mysql> select @x;
    +------+
    | @x   |
    +------+
    |   11 |
    +------+

    十一、loop配合leave
    leave:跳出语句块

    DELIMITER $$
    CREATE  PROCEDURE small_exit(OUT p1 INTEGER,OUT p2 INTEGER)
       BEGIN
          SET p1 = 1;
          SET p2 = 1;
          block1: BEGIN 
             LEAVE block1;    --》就不再执行下面那个p2=3了!!
             SET p2 = 3;  
          END block1;  
          SET p1 = 4;    
       END$$
    DELIMITER ;
    mysql> call small_exit(@a,@b);
    Query OK, 0 rows affected (0.00 sec)
    mysql> select @a,@b;
    +------+------+
    | @a   | @b   |
    +------+------+
    |    4 |    1 |
    +------+------+
    1 row in set (0.00 sec)

    loop

    DELIMITER $$
    CREATE  PROCEDURE wait_n(IN wait_seconds INTEGER)
       BEGIN                                                     ---》PSinterval 间隔
          DECLARE end_time datetime DEFAULT now() + INTERVAL wait_seconds SECOND; 
          wait_loop:LOOP
            IF now() > end_time THEN
               LEAVE wait_loop;
            END IF;   
          END LOOP wait_loop;      
       END$$
    DELIMITER ;
    mysql> call wait_n(10);
    Query OK, 0 rows affected (10.55 sec)

    while:先判断再执行
    repeat…until:先执行再判断
    loop:判断可以放在loop…end loop之间的任意位置
    iterate:跳出本次循环

    十二、ITERATE

    DELIMITER $$
    CREATE PROCEDURE doiterate3(p1 INT,p2 INT)
    BEGIN
      label1: LOOP
        SET p1 = p1 + 1;
        SET p2 = p2 + 1;
        IF p1 < 10 THEN
            select p1;
          ITERATE label1;    --》跳出本次label1循环!继续下次label1循环。
           select p2;    --》一直没执行
        END IF;
        LEAVE label1;
      END LOOP label1;
      SET @x = p1;
    END$$
    DELIMITER ;
    mysql> call doiterate3(10,10);    --》直接就执行leave label1
    Query OK, 0 rows affected (0.01 sec)
    mysql> call doiterate3(1,1);    ---》显示p1=2,3,4...9
    +------+
    | p1   |
    +------+
    |    2 |
    +------+
    1 row in set (0.00 sec)
    +------+
    | p1   |
    +------+
    |    3 |
    +------+
    1 row in set (0.00 sec)

    十三、select info经典用法

    DELIMITER $$
    CREATE  PROCEDURE total_penalties_player(
      IN p_playerno INTEGER,
      OUT total_penalties DECIMAL(8,2))   
     BEGIN     
       SELECT sum(amount)        ---》去掉into的select只能返回一行数据!
         INTO total_penalties  --》把select 的结果into给(多个)变量!!
         FROM PENALTIES
         WHERE playerno = p_playerno;            
     END$$
    DELIMITER ;
    mysql> call total_penalties_player(44,@a);  ---》计算44号人的罚款总额,结果赋给@a
    Query OK, 1 row affected (0.01 sec)
    mysql> select @a;
    +--------+
    | @a     |
    +--------+
    | 130.00 |
    +--------+
    1 row in set (0.00 sec)

    小结:

    • 1.经典的方式:将select返回的多列单行数据赋值给相应的变量(一个列对应一个变量)
    • 2.这些变量经常是out参数
    • 3.也就是变相的将select的结果传给了存储过程,让外面的程序可见。

    例2:into给多个参数:

    DELIMITER $$
    CREATE  PROCEDURE get_address(
      IN p_playerno SMALLINT,
      OUT p_street VARCHAR(30),
      OUT p_houseno VARCHAR(4),
      OUT p_town VARCHAR(30),
      OUT p_postcode VARCHAR(6))   
     BEGIN     
       SELECT street, houseno, town, postcode
         INTO p_street, p_houseno, p_town, p_postcode
         FROM PLAYERS
         WHERE playerno = p_playerno;            
     END$$
    DELIMITER ;
    mysql> call get_address(44,@a,@b,@c,@d);
    Query OK, 1 row affected (0.01 sec)
    mysql> select @a,@b,@c,@d;
    +--------------+------+-----------+--------+
    | @a           | @b   | @c        | @d     |
    +--------------+------+-----------+--------+
    | Lewis Street | 23   | Inglewood | 4444LJ |
    +--------------+------+-----------+--------+
    1 row in set (0.00 sec)
  • 相关阅读:
    19凡路国庆小作业的题解集合(qwq只是我出的题,我会标明出处的)
    一个for打印99乘法表(这是一种实现方式,可以多种方式的)
    采访学长所得
    洛谷P1028 数的计算
    ccf 2019_03_2 二十四点
    ccf 201812-1 小明上学
    洛谷P3387 【模板】缩点
    洛谷P3216 [HNOI2011]数学作业
    洛谷P1471 方差
    HDU 4114 Disney's FastPass
  • 原文地址:https://www.cnblogs.com/lpeng94/p/12546474.html
Copyright © 2020-2023  润新知