码迷,mamicode.com
首页 > 数据库 > 详细

《MySQL必知必会》[05] 存储过程和游标

时间:2017-12-05 13:28:24      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:percent   get   handle   类型   val   1.5   number   例子   pen   


1、存储过程

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

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

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

1.1 基本语句

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

1.2 创建

然后,根据刚才我们说到的返回包含营业税的订单总额,创建如下存储过程:
  1. -- Name: ordertotal
  2. -- Parameters: onumber = order number
  3. -- taxable = 0 if not taxable, 1 if taxable
  4. -- ototal = order total variable
  5. CREATE PROCEDURE ordertotal(
  6. IN onumber INT,
  7. IN taxable BOOLEAN,
  8. OUT ototal DECIMAL(8, 2)
  9. ) COMMENT ‘Obtain order total, optionally adding tax‘
  10. BEGIN
  11. --Declare variable for total
  12. DECLARE total DECIMAL(8, 2);
  13. --Declare tax percentage
  14. DECLARE taxrate INT DEFAULT 6;
  15. --GET the order total
  16. SELECT Sum(item_price*quantity)
  17. FROM orderitems
  18. WHERE order_num = onumber
  19. INTO total;
  20. --Is this taxable
  21. IF taxable THEN
  22. SELECT total+(total/100*taxrate) INTO total;
  23. END IF;
  24. SELECT total INTO ototal;
  25. END;

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

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

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

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

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

1.3 执行

在1.2我们定义了存储过程ordertotal(),则执行方式为:
  1. --不含营业税
  2. CALL ordertotal(20005, 0, @total);
  3. SELECT @total
  4. +----------+
  5. | @total |
  6. +----------+
  7. | 149.87 |
  8. +----------+
  9. --包含营业税
  10. CALL ordertotal(20005, 1, @total);
  11. SELECT @total
  12. +-----------------+
  13. | @total |
  14. +-----------------+
  15. | 158.862200000 |
  16. +-----------------+

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

1.4 检查

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

1.5 删除

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



2、游标

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

2.1 创建游标

使用DECLARECURSOR关键字:
  1. CREATE PROCEDURE processorders()
  2. BEGIN
  3. DECLARE ordernumbers CURSOR
  4. FOR
  5. SELECT order_num FROM orders;
  6. END;

2.2 打开和关闭游标

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

2.3 使用游标数据

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

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

  1. SELECT * FROM ordertotals;
  2. +---------+---------+
  3. | 20005 | 158.86 |
  4. | 20006 | 58.30 |
  5. | 20007 | 1060.00 |
  6. | 20008 | 132.50 |
  7. | 20009 | 40.78 |
  8. +---------+---------+


《MySQL必知必会》[05] 存储过程和游标

标签:percent   get   handle   类型   val   1.5   number   例子   pen   

原文地址:http://www.cnblogs.com/deng-cc/p/7986087.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!