使用存储过程
Posted 霖行
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用存储过程相关的知识,希望对你有一定的参考价值。
使用存储过程
本章介绍什么是存储过程,为什么要使用存储过程以及如何使用存储过程,并且介绍创建和使用存储过程的基本语法。
存储过程
目前使用的大多数SQL语句都是针对一个或多个表的单条语句。但实践中经常会有一个完整的操作需要多条语句,例如:
- 为了处理订单,需要核对以保证库存中有相应的物品。
- 如果库存有物品,这些物品需要预定以便不将它卖给别人,并且库存量需要减少。
- 库存中没有的物品需要订购,这需要与供应商进行交互。
- 关于哪些物品入库(并且可以立即发货)和哪些物品退订,需要通知相应的客户。
执行这个处理需要针对多条表的多条mysql语句,并且,需要执行的具体语句及次序也不是固定的。因此我们可以创建存储过程,简单来说,它就是为以后的使用而保存的一条或多条MySQL语句的集合。
为什么要使用存储过程
使用存储过程的理由:
- 通过把处理封装在容易使用的单元中 ,简化复杂的操作。
- 由于不要求反复建立一系列处理步骤 ,这保证了数据的完整性。
- 简化对变动的管理。
- 提高性能 。使用存储过程比使用单独的SQL语句快。
- 存在一些只能在单个请求中的MySQL元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码。
总的来说,使用存储过程有3个主要的好处,简单、安全、高性能。
但,有好有坏,存储过程有一些缺陷:
- 一般存储过程的编写比基本SQL语句复杂。
- 你可能没有创建存储过程的安全访问权限。许多数据库管理员限制了存储过程的创建权限,仅允许用户使用存储过程,但不允许创建存储过程。
使用存储过程
使用存储过程需要知道如何执行它们。存储过程的执行远比其定义更经常遇到,故我们先了解如何执行存储过程,再了解创建和使用存储过程。
执行存储过程
MySQL称存储过程的执行为 调用 ,因此MySQL执行存储过程的语句为CALL。CALL接受存储过程的名字以及需要传递给它的任意参数:
CALL productpricing(@pricelow, @pricehigh, @priceaverage);
执行名为productpricing的存储过程,它计算并返回产品的最低、最高和平均价格。
存储过程可以显示也可以不显示结果。
创建存储过程
创建一个返回产品平均价格的存储过程:
mysql> DELIMITER //
mysql> CREATE PROCEDURE productpricing()
-> BEGIN
-> SELECT Avg(prod_price) AS priceaverage
-> FROM products;
-> END //
Query OK, 0 rows affected (0.04 sec)
mysql> DELIMITER ;
此存储过程名为productpricing,用CREATE PROCEDURE productpricing()语句定义。如果存储过程接受参数,它们将在()中列出。BEGIN和END语句用来限定存储过程体。
MySQL处理这段代码时,它创建一个新的存储过程productpricing,没有返回数据。
MySQL命令行客户机的分隔符 默认的MySQL语句分隔符为 ‘;’ 。MySQL命令行实用程序也使用 ‘;’ 作为语句分隔符。在创建存储过程时,存储过程体中的 ‘;’ 会被命令行解析为语句结束,从而提交不全代码,导致报错。
我们通过 临时更改 命令行实用程序的语句分隔符,来避免冲突。DELIMITER //告诉命令行使用//代替;作为语句分隔符,语句中END后接//表示语句结束。
除\\符合外,任何字符都可以用作语句分隔符。若使用其他客户端,需将DELIMITER行删除,并将END后的//改为;。
使用此存储过程:
mysql> CALL productpricing();
+--------------+
| priceaverage |
+--------------+
| 16.133571 |
+--------------+
1 row in set (0.04 sec)
Query OK, 0 rows affected (0.04 sec)
删除存储过程
为删除存储过程,可以使用DROP PROCEDURE关键字:
mysql> DROP PROCEDURE productpricing;
Query OK, 0 rows affected (0.02 sec)
删除存储过程只需给出存储过程名,不需要带括号与参数。
- 仅当存在时删除 如果指定的过程不存在,则会产生一个错误。可以使用DROP PROCEDURE IF EXISTS,仅当存储过程存在时执行命令。
使用参数
productpricing它简单地显示SELECT语句的结果。但一般,存储过程并不显示结果,而是把结果返回给你指定的变量。
- 变量(variable) 内存中一个特定的位置,用来临时存储数据。
productpricing实用版:
mysql> DELIMITER //
mysql> CREATE PROCEDURE productpricing(
-> OUT pl DECIMAL(8,2),
-> OUT ph DECIMAL(8,2),
-> OUT pa DECIMAL(8,2)
-> )
-> BEGIN
-> SELECT Min(prod_price)
-> INTO pl
-> FROM products;
-> SELECT Max(prod_price)
-> INTO ph
-> FROM products;
-> SELECT Avg(prod_price)
-> INTO pa
-> FROM products;
-> END //
Query OK, 0 rows affected (0.01 sec)
mysql> DELIMITER ;
此存储过程接受3个参数:pl存储产品最低价格,ph存储产品最高价格,pa存储产品平均价格。每个参数必须具有指定的类型。关键字OUT指出此参数从存储过程中传出一个值(给调用者)。MySQL支持IN(传递给存储过程)、OUT(从存储过程传出)和INOUT(对存储过程传入和传出)类型的参数。 存储过程体中检索出的值,通过INTO关键字保存到相应变量。
- 参数的数据类型 存储过程的参数允许的数据类型与表中使用的数据类型相同。因此,记录集不能作为参数进行传递。
为调用此存储过程,必须指定三个变量名:
mysql> CALL productpricing(@pricelow, @pricehigh, @priceaverage);
Query OK, 1 row affected, 1 warning (0.01 sec)
- 变量名 所有MySQL变量都必须以@开始。
此语句不显示数据,它返回可以显示的变量。
查看变量:
mysql> SELECT @priceaverage;
+---------------+
| @priceaverage |
+---------------+
| 16.13 |
+---------------+
1 row in set (0.00 sec)
创建存储过程ordertotal接受订单号并返回该订单的合计:
mysql> DELIMITER //
mysql> CREATE PROCEDURE ordertotal(
-> IN onumber INT,
-> OUT ototal DECIMAL(8,2)
-> )
-> BEGIN
-> SELECT Sum(item_price*quantity)
-> FROM orderitems
-> WHERE order_num = onumber
-> INTO ototal;
-> END //
Query OK, 0 rows affected (0.01 sec)
mysql> DELIMITER ;
onumber定义为IN,外部将订单号传入存储过程。ototal定义为OUT,从存储过程返回合计。
调用新存储过程:
mysql> CALL ordertotal(20005, @total);
Query OK, 1 row affected (0.01 sec)
显示合计:
mysql> SELECT @total;
+--------+
| @total |
+--------+
| 149.87 |
+--------+
1 row in set (0.00 sec)
建立智能存储过程
以上都是存储过程对MySQL简单的SELECT语句进行封装。而存储过程的威力更多在于,在存储过程中包含业务规则和智能处理中。
考虑一个场景,你需要获得订单合计,但需要对合计添加营业税,但只针对个别用户。你需要做以下几件事;
- 获得合计。
- 把营业税有条件地添加到合计。
- 返回合计(带或不带税)
存储过程完整代码:
-- 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
-- Yes, so add taxrate to the total
SELECT total+(total/100*taxrate) INTO total;
END IF;
-- Add finally, save to out variable
SELECT total INTO ototal;
END;
此存储过程添加了注释(前面放--),在面对复杂代码时,注释必不可少,方便以后对代码的理解。添加了布尔参数taxable,值为真表示需要增加税。存储过程体中,用DECLARE语句定义了两个局部变量。DECLARE要求指定变量名和数据类型,它也支持可选的默认值。
调用存储过程:
mysql> CALL ordertotal(20005, 0, @total);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT @total;
+--------+
| @total |
+--------+
| 149.87 |
+--------+
1 row in set (0.00 sec)
mysql> CALL ordertotal(20005, 1, @total);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT @total;
+--------+
| @total |
+--------+
| 158.86 |
+--------+
1 row in set (0.00 sec)
BOOLEAN值指定为1表示真,指定为0表示假(实际上,非0即真)。
- COMMENT关键字 存储过程在CREATE PROCEDURE语句中包含了一个COMMENT值。这不是必须的,但若给出,此值将在SHOW PROCEDURE STATUS的结果中显示。
- IF语句 此例给出了MySQL的IF语句的基本用法。IF语句还支持ELSEIF和ELSE子句。
检查存储过程
为显示创建存储过程的CREATE语句,使用SHOW CREATE PROCEDURE语句:
mysql> SHOW CREATE PROCEDURE ordertotal;
为了获得包括何时、由谁创建等详细信息的存储过程列表,可使用SHOW PROCEDURE STATUS。
- 限制过程状态结果 SHOW PROCEDURE STATUS列出所有存储过程。为指定查询,可使用LIKE指定一个过滤模式。
SHOW PROCEDURE STATUS LIKE 'ordertotal';
以上是关于使用存储过程的主要内容,如果未能解决你的问题,请参考以下文章