zoukankan      html  css  js  c++  java
  • 《MySQL必知必会》[05] 存储过程和游标


    1、存储过程

    存储过程是什么,简单来讲,就像Java中的方法(函数),不过它是SQL世界中的方法。

    大部分时候,我们所使用都是单条SQL,用来针对一个或多表连接。但是也有情况,是据判断先对表A执行操作,变动后再结合表B进行操作。即SQL的执行可能需要考虑包含业务规则在内的智能处理。封装操作的好处就不过多说明,无非是简化,复用,降低耦合等,同时,它还具有更高的性能。

    考虑这种业务情况,现在你需要获得订单总额,但同时需要增加营业税,且只针对某些顾客,那么你需要:
    • 获得基本的订单总额
    • 将营业税有条件地添加到合计中
    • 返回合计

    1.1 基本语句

    先看基本的语句,然后再看示例,就豁然开朗了:
    --创建存储过程 
    CREATE PROCEDURE <存储过程的名称>(<变量的类型定义>)
    BEGIN
      <执行操作>
    END;
    
    --执行存储过程
    CALL <存储过程的名称>(<@变量名>);
    
    --删除存储过程
    DROP PROCEDURE <存储过程的名称>;

    1.2 创建

    然后,根据刚才我们说到的返回包含营业税的订单总额,创建如下存储过程:
    -- Name: ordertotal
    -- Parameters: onumber = order number
    --             taxable = 0 if not taxable, 1 if taxable
    --             ototal  = order total variable
    
    CREATE PROCEDURE ordertotal(
      IN  onumber INT,
      IN  taxable BOOLEAN,
      OUT ototal DECIMAL(8, 2)
    ) COMMENT 'Obtain order total, optionally adding tax'
    BEGIN
      --Declare variable for total
      DECLARE total DECIMAL(8, 2);
      --Declare tax percentage
      DECLARE taxrate INT DEFAULT 6;
      
      --GET the order total
      SELECT Sum(item_price*quantity)
      FROM orderitems
      WHERE order_num = onumber
      INTO total;
    
      --Is this taxable
      IF taxable THEN
        SELECT total+(total/100*taxrate) INTO total;
      END IF;
    
      SELECT total INTO ototal;
    END;

    看起来这么长好像挺唬人,其实很清楚:
    CREATE PROCEDURE ordertotal(
      IN  onumber INT,
      IN  taxable BOOLEAN,
      OUT ototal DECIMAL(8, 2)
    ) COMMENT 'Obtain order total, optionally adding tax'
    • 使用CREATE PROCEDURE关键词创建了名为ordertotal的存储过程
    • 该存储过程定义了三个变量,IN表示要求输入的参数,OUT表示输出的结果。INT、BOOLEAN等表示变量的数据类型
    • COMMENT非必需,如果有,那么在SHOW PROCEDURE STATUS的结果时会显示(简单说,类似于方法的说明)

    BEGIN
      ...
    END;
    • BEGIN和END用来界定存储过程操作执行的语句

      --Declare variable for total
      DECLARE total DECIMAL(8, 2);
      --Declare tax percentage
      DECLARE taxrate INT DEFAULT 6;
      
      --GET the order total
      SELECT Sum(item_price*quantity)
      FROM orderitems
      WHERE order_num = onumber
      INTO total;
    • DECLARE用来定义存储过程中的局部变量
    • INTO表示赋值到变量

      --Is this taxable
      IF taxable THEN
        SELECT total+(total/100*taxrate) INTO total;
      END IF;
    • IF <boolean> THEN <do something> END IF 为条件执行语句,记得END IF结尾

    假如用Java来写的话,大概是这么个意思:
    public void ordertotal(int onumber, boolean taxable, double ototal) {
    
        double total;
        int taxrate = 6;
        
        total = getOrderTotal(onumber);
        if (taxable) {
            total += total / (100 * taxrate);
        }
    
        ototal = total;
    }

    1.3 执行

    在1.2我们定义了存储过程ordertotal(),则执行方式为:
    --不含营业税
    CALL ordertotal(20005, 0, @total);
    SELECT @total
    
    +----------+
    |  @total  |
    +----------+
    |  149.87  |
    +----------+
    
    --包含营业税
    CALL ordertotal(20005, 1, @total);
    SELECT @total
    
    +-----------------+
    |      @total     |
    +-----------------+
    |  158.862200000  |
    +-----------------+

    定义时我们说过,IN表示定义输入,OUT表示定义输出,所以这里的三个变量中,前两者由调用者传入,而第三个变量,则作为返回结果的变量。
    调用存储过程时,用于临时存储返回数据的变量必须以@开头

    1.4 检查

    用来显示“创建某个存储过程的CREATE语句”,使用SHOW CREATE PROCEDURE语句:
    SHOW CREATE PROCEDURE ordertotal;

    1.5 删除

    DROP PROCEDURE ordertotal;
    注意,检查和删除存储过程,都不用加后面的(),只需要给出存储过程的名称即可。



    2、游标

    在检索出来的行中,前进或者后退一行或多行,就需要用到所谓的“游标”。游标不是某个SELECT语句,但是它是被该语句检索出来的结果集,另外,MySQL游标只能用于存储过程(和函数)。

    2.1 创建游标

    使用DECLARECURSOR关键字:
    CREATE PROCEDURE processorders()
    BEGIN
      DECLARE ordernumbers CURSOR
      FOR
      SELECT order_num FROM orders;
    END;

    2.2 打开和关闭游标

    因为游标局限于存储过程,所以如果存储过程处理完成后,游标就会消失。所以往往在存储过程中要关键字OPEN进行打开。另,游标相关的SELECT查询语句,在定义时是不执行的,在OPEN时才执行查询,存储检索出的数据以供浏览和滚动。在游标使用完成后,使用CLOSE进行关闭:
    CREATE PROCEDURE processorders()
    BEGIN
      --Declare
      DECLARE ordernumbers CURSOR
      FOR
      SELECT order_num FROM orders;
    
      --Open
      OPEN ordernumbers;
      
      --Close
      CLOSE ordernumbers;
    END;

    2.3 使用游标数据

    打开游标之后,我们就可以使用关键字FETCH访问数据了,FETCH是从第一行开始,获取当前行的数据,每次执行后会移动内部行指针,再次调用FETCH则会检索到下一行(不会重复读取同一行):
    CREATE PROCEDURE processorders()
    BEGIN
      --Declare
      DECLARE o INT;
      DECLARE ordernumbers CURSOR
      FOR
      SELECT order_num FROM orders;
     
      --Open
      OPEN ordernumbers;
     
      --Get
      FETCH ordernumbers INTO o;  
     
      --Close
      CLOSE ordernumbers;
    END;

    看一个复杂些的例子:
    CREATE PROCEDURE processorders()
    BEGIN
      --Declare local variables
      DELCARE done BOOLEAN DEFAULT 0;
      DECLARE o    INT;
      DECLARE t    DECIMAL(8,2);
    
      --Declare cursor
      DECLARE ordernumbers CURSOR
      FOR
      SELECT order_num FROM orders;
     
      --Declare continue handler
      DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
    
      --Create a table to store the results
      CREATE TABLE IF NOT EXISTS ordertotals(order_num INT, total DECIMAL(8,2));  
    
      --Open the cursor
      OPEN ordernumbers;
     
      --Loop through all rows
      REPEAT
        FETCH ordernumbers INTO o;
        CALL ordertotal(o, 1, t);
        INSERT INTO ordertotals(order_num, total) VALUES(o, t);
      UNTIL done END REPEAT;
    
      --Close the cursor
      CLOSE ordernumbers;
    END;
    • 以上存储过程,游标不断读取订单号,并以此为参调用另一个存储过程,将最终的值填入到表ordertotals中
    • CONTINUE HANDLER 是在条件出现时执行的代码,SQLSTATE '02000' 表没有找到更多的行(MySQL错误代码)

    SELECT * FROM ordertotals;
    
    +---------+---------+
    |  20005  |  158.86 |
    |  20006  |   58.30 |
    |  20007  | 1060.00 |
    |  20008  |  132.50 |
    |  20009  |   40.78 |
    +---------+---------+


  • 相关阅读:
    静态初始化块和main方法哪个先被执行?
    Java中的构造方法
    Java中的局部变量、成员变量和静态变量
    经典算法冒泡排序java版
    Java里数组的三种初始化方式
    聊天,发朋友圈可以不打字,但是表情怎么能少呢?那么如何用win10自带的微软拼音输入法打出表情呢?
    java打印实心10*10正方形, 空心10*10正方形
    安卓工程目录
    (1)开源中国android客户端源码分析
    认识电脑的开机流程与主引导分区(MBR)
  • 原文地址:https://www.cnblogs.com/deng-cc/p/7986087.html
Copyright © 2011-2022 走看看