迄今为止,使用的大多数SQL语句都是针对一个或者多个表的单条语句,并非所有操作都这么简单,经常会有一个完整的操作需要多条语句才能完成。执行这个操作需要针对许多表的MySQL语句。此外,需要执行的具体语句及其次序也不是固定的。
那么,怎样编写此代码?可以单独编写每条语句,并根据结果有条件的执行另外的语句。在每次需要这个处理时(以及每个需要它的应用中)都必做这些工作。
可以创建存储过程。存储过程简单的来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。可以将其视为批文件,虽然它的作用不仅限于批处理。
为什么要使用存储过程?
1.通过吧处理封装在容易使用的单元中,简化复杂的操作性。
2.由于不要求反腐建立一系列处理步骤,这就保证了数据的完整性。如果所有开发人员和应用程序都使用同一(试验和测试)存储过程,则所使用的代码都是相同的。这一点的延伸就是防止错误。需要执行的步骤越多, 出错的可能性就越大。防止错误数据保证了数据的一致性。
3.简化对变动的管理。如果表名、列名或业务逻辑(或别的内容)有变化,只需要更改存储的过程,使用它的人员甚至不需要知道这些变化。这一点的延伸就是安全性。通过存储过程限制对基础数据的访问减少了数据讹误(无意识的或别的原因所导致的数据讹误)的机会。
4.提高性能。因为使用存储过程比使用单独的SQL语句要快。
5.存在一些只能用在单个请求中的MySQL元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码。
换句话说,使用存储过程有3个好处:即简单、安全、高性能。
但是也有缺陷:
1.一般来说,存储过程的编写比基本SQL语句要复杂,需要更高的技能和丰富的经验。
2.你可能没有创建存储过程的安全访问权限。许多数据库管理员限制存储过程的创建权限,允许用户使用存储过程,但不允许他们创建存储过程。
MySQL将编写存储过程的安全和访问与执行存储过程的安全和访问区分开来。
使用存储过程:
存储过程的执行比其定义更经常遇到。
执行存储过程:
MySQL称存储过程的执行为调用,因此MySQL执行存储过程的语句为CALL。CALL接收存储过程的名字及其需要传递给它的参数。
例子:
CALL productpricing(@pricelow,
@pricehigh,
@priceaverage);
其中,执行名为productpricing的存储过程,它计算并返回产品的最低、最高个平均价格。
创建存储过程:
例子:一个返回产品品骏价格的存储过程:
CREATE PROCEDURE productpricing()
BEGIN
SELECT Avg(prod_price) AS priceaverage
FROM products;
END;
此存储过程名为:productpricing,用CREATE PROCEDURE productpricing()语句定义。如果存储过程接受参数,它们将在()中列举出来。此存储过程没有参数,但后面的()仍然需要。BEGIN和END用来限定存储过程体。过程本身仅是一个简单的SELECT语句。
MySQL命令行客户机的分隔符
如果你使用的是mysql命令行实用程序。默认MySQL的默认分隔符是;。mysql命令行实用程序也使用;作为语句分隔符。如果命令行实用程序要解释存储过程自身的;字符,则它们最终不会成为存储过程的部分,这会使存储过程当中的SQL语句出现错误。解决办法是临时更高命令行实用程序的语句分隔符,如下所示:
DELIMITER //
CREATE PROCEDURE productpricing()
BEGIN
SELECT Avg(prod_price) AS priceaverage
FROM products;
END //
DELIMITER ;
其中,DELIMITER // 告诉命令行实用程序使用 //作为新的语句分隔符,可以看到标志存储过程的END定义为END // 而不是END; 。这样,存储过程体内的;仍然保持不动,并且正确的传递给数据库引擎。最后,为恢复为原来的语句分隔符,可以使用DELIMITER ;。除 \之外,任何字符都可以作为语句分隔符。
那么如何使用这个存储过程呢?如下所示:
CALL productprricing();
删除存储过程:
存储过程建立之后,被保留在服务器内以供使用,直至被删除。删除命令从服务器中删除存储过程。名利如下:
DROP PROCEDURE productpricing;
注意:后面没有(),只需要给出删除的存储过程名字即可。
仅当存在时删除,如果指定的存储过程不存在,则DROP PROCEDURE将产生一个错误。当过程存在想删除它是,可以使用DROP PROCEDURE ID EXISTS。
使用参数:
productpricing只是一个简单的存储过程,它简单的显示SELECT语句的结果。一般,存储过程并不现实结果,而是把结果返回给你指定的变量。变量(variable)内存中一个特定的位置,用来存储临时数据。
以下是productpricing的修改版本(如果不先删除词存储过程,则不能创建它):
CREATE PROCEDURE productpricing(
OUT p1 DECIMAL(8,2),
OUT ph DECIMAL(8,2),
OUT pa DECIMAL(8,2)
)
BEGIN
SELECT Min(prod_price)
INTO p1
FROM products;
SELECT Max(prod_price)
INTO ph
FROM products;
SELECT Avg(prod_price)
INTO pa
FROM products;
END;
此存储过程接受3个参数,每个参数都必须具有制定的类型,这里用的是十进制。关键字OUT指出相应的参数用来存储过程传出一个值(返回给调用者)。MySQL支持IN(传递给存储过程)、OUT(从存储过程中传出,如这里所用)和INOUT(对存储过程传入和传出)类型的参数。存储过程的代码位于BEGIN和END语句内,如前所见,它们是一些列SELECT语句,用来检索值,然后保存到相应的变量(通过指定INTO关键字)。
由于词存储过程要求三个参数,因此必须传递3个参数,不多也不少。所以,这条CALL语句给出3个参数。它们是存储过程将保存结果的3个变量的名字。
所有MySQL变量都必须以@开始。
在调用时,这条创建的存储过程语句并不显示任何数据。它返回以后可以显示(或者在其它处理中使用)的变量。
为了检索出产品的平均价格,可以如下进行:
SELECT @priceaverage;
为了可以获得3个值,可以使用如下语句:
SELECT @pricehigh,@pricelow,@priceaverage;
下面是另外一个例子,这次使用IN和OUT参数。ordertotal接受订单号并返回该订单的合计:
CREATE PROCEDURE ordertotal(
IN onumber INT,--订单号传入存储过程
OUT ototal DECIMAL(8,2)--从存储过程返回合计
)
BEGIN
SELECT Sum(item_pirce*quantity)
FROM orderitems
WHERE order_num = onumber
INTO ototal;--存储计算出来的合计
END;
--为了调用这个存储过程,可以使用以下语句:
CALL ordertotal(2005,@total);--必须给存储过程传递两个参数,第一个为订单号,第二个为包含计算出来的合计的变量名;
--为了显示此合计,可以如下进行:
SELECT @total
建立智能存储过程:
迄今为止所有的存储过程基本上都是封装MySQL简单的SELECT查询。只有在存储过程内包包含业务规则和智能处理时,存储过程的威力才显现出来。
考虑这个场景,你需要获得与以前一样的订单合计,但需要对合计增加营业税,不过只针对某些顾客(或许是你所在省份的那些顾客)。那么,需要做以下事情:
1.获得合计(与以前一样);
2.把营业税带条件的添加到合计;
3.返回合计(带或者不带税);
存储过程完整如下:
CREATE PROCEDURE ordertotal(
IN onumber INT,
IN taxtable 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 taxtable?
IF taxtable THEN
-- YES,so add taxrate to the total
SELECT total+(total/100*taxrate) INTO total;
END IF;
--And finally,save the out variable
SELECT total INTO ototal;
END;
次存储过程做了很大的变动。首先,增加了注释(前面方式--)。添加了另外一个参数taxable,它是一个布尔值(如果增加税为真,否则为假)。在存储过程体中,用DECLARE语句定义了两个局部变量。DECLARE要求制定变量名和数据类型,它支持可选得默认值(这个例子中的taxrate的默认被设置为6%)。SELECT语句已经改变,因此将其结果存储到total(局部变量,而不是ototal).IF 语句检查taxtable是否为真,如果为真,则用另一SELECT语句增加营业税到局部变量total。最后,用另一SELECT语句将total(它增加或者不增加营业税)保存到ototal。
这显然是一个更高级,功能更强的存储过程。为试验它,利用以下两条语句:
CALL ordertotal(2005,0,@total);
SELECT @total;
CALL ordertotal(2005,1,@total);
SELECT @total;
IF语句还支持ELSEIF 和ELSE语句(前者还使用THEN子句,后者不使用)。
检查存储过程:
为显示用来创建一个存储过程的CREATE语句,使用SHOW CREATE PROCEDURE语句。
SHOW CREATE PROCEDURE ordertotal;
为了获得包括何时、有谁创建等详细信息的存储过程列表,使用SHOW PROCEDURE status。
SHOW PROCEDURE status 列出所有存储过程,为限制其输出,可以使用LIKE指定一个过滤模式,例如:
SHOW PROCEDURE STATUS LIKE 'ordertotal';