MySQL 7 存储过程、游标、触发器

1. 存储过程

迄今为止,大多数SQL语句都是针对一个或多个表的单条语句。有一些操作会有一个完整的操作需要多条语句才能完成。

存储过程简单来说就是为以后的使用而保存的一条或多跳=条MySQL语句的集合。可将其视为批文件,虽然它们的作用不仅限于批处理。

存储过程的优点:

通过把处理封装在容易使用的单元中,简化复杂的操作;由于不要求反复建立一系列处理步骤,保证了数据的完整性,防止错误的发生可能;

简化对变动的管理,安全性;提高性能;存在一些只能用在单个请求中的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处理这段代码时,它创建一个新的存储过程productpricing,没有返回数据,因为这段代码并未调用存储过程,这里只是为以后使用而创建它。

由上面看出,存储过程中出现了多个;,如果使用mysql命令行,命令行的语句分隔符也是;,需要一种方法来避免出现错误。

  DELIMITER //

  CREATE PROCEDURE productpricing()

  BEGIN

    SELECT AVG(prod_price) AS priceaverage  

    FROM products;

  END //

  DELIMITER;

DELIMITER告诉了1命令行使用程序使用//作为新的语句结束分隔符。后一个DELIMITER后接 ; 表示恢复为原来的分隔符。

然后可以CALL这个存储过程:

  CALL productpricing();

执行刚创建的存储过程并显示返回的结果。因为存储过程实际上是一种函数,所以存储过程名后需要有()符号,即使无参数也要有。

删除存储过程:

存储过程在创建之后,被保存在服务器上以供使用,直至被删除。删除命令从服务器中删除存储过程。

删除存储过程可用DROP PROCEDURE:

  DROP PROCEDURE productpricing;

这条语句删除刚创建的存储过程。这是不用加上()。

存储过程使用参数:

变量variable:内存中一个特定的位置,用来临时存储数据。

  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;

此存储过程接受3个参数。每个参数必须具有指定的类型。关键字OUT指出相应的参数用来从存储过程传出一个值(返回给调用者)。

MySQL支持IN(传递给存储过程)、OUT(从存储过程传出)和INOUT(对存储过程传入和传出)类型的参数。

存储过程的代码位于BEGIN和END语句内,它们是一系列SELECT语句,用来检索值,然后保存到相应的变量中(通过INTO关键字)。

为了调用此修改的存储过程,必须指定3个变量名:

  CALL productpricing(@pricelow, @pricehigh, @priceaverage);

由于此存储过程要求3个参数,因此必须正好传递3个参数,不多也不少。这个例子中是存储过程将保存结果的3个变量的名字。

在调用时,这条语句不显示任何数据,它返回以后可以显示(或在其它处理中使用)的变量。

  SELECT @priceaverage;

  SELECT @pricehigh, @pricelow, @priceaverage;

变量名:所有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;

  CALL ordertotal(20005, @total);

必须传递给这个存储过程两个参数。

使用智能存储:

  -- Name: ordertotal

  --

  CREATE PROCEDURE ordertotal(

    IN onumber INT,

    IN taxable BOOLEAN,

    OUT ototal DECIMAL(8,2)

  )COMMENT 'Obtain order total, optionally adding tax'

  BEGIN

    DECLARE total DECIMAL(8,2);

    DECLARE taxrate INT DEFAULT 6;

    SELECT SUM(item_price*quantity)

    FROM orderitems

    WHERE order_num = onumber

    INTO total;

    

    IF taxable THEN

      SELECT total+(total/100*taxrate) INTO total;

    END IF;

    

    SELECT total INTO ototal;

  END;

此存储过程:增加了注释(前面放置--)。用DECLARE语句定义了两个局部变量。DECLARE要求指定变量名和数据类型,它也支持可选的默认值,用DEFAULT跟着类型后面。

IF语句检查条件是否为真,如果为真怎么做,否则怎么做。

COMMENT关键字:其将在SHOW PROCEDURE STATUS的结果中显示。

IF语句:IF语句还支持ELSEIF和ELSE子句。

检查存储过程:

为显示用来创建一个存储过程的CREATE语句,使用SHOW CREATE PROCEDURE语句:

  SHOW CREATE PROCEDURE ordertotal;

获得了包括何时、由谁创建等详细信息的存储过程列表。

2. 使用游标

游标cursor:是一个存储在MySQL服务器上的数据库查询,它不是一条SELECT语句,而是被该语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。

游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或做出更改。

只能用于存储过程:MySQL游标只能用于存储过程(和函数)。

使用游标:

在能够使用游标前,必须声明(定义)它。这个过程实际上没有检索数据,它只是定义要使用的SELECT语句。

一旦声明后,必须打开游标以供使用。这个过程用前面定义的SELECT语句把数据实际检索出来。

对于填有数据的游标,根据需要取出(检索)各行。

在结束游标使用时,必须关闭游标。

创建游标:

游标用DECLARE语句创建。DECLARE命名游标,并定义相应的SELECT语句,根据需要带WHERE和其它子句。

  CREATE PROCEDURE processorders()

  BEGIN

    DECLARE ordernumbers CURSOR

    FOR

    SELECT order_num FROM orders;

  END;

这个存储过程并没有做很多事情,DECLARE语句用来定义和命名游标,这里为ordernumbers。存储过程处理完成后,游标就消失(因为它局限于存储过程)。

打开和关闭游标:

游标用OPEN CURSOR语句来打开:

  OPEN ordernumbers;

在处理OPEN语句时执行查询,存储检索出的数据以供浏览和滚动。

  CLOSE ordernumbers;

CLOSE释放游标使用的所有内部内存和资源,因此在每个游标不再需要时都应该关闭。

在一个游标关闭后,如果没有重新打开,则不能使用它。但是,使用声明过的游标不需要再次声明,用OPEN语句打开它就可以了。

隐含关闭:如果不明确关闭游标,MySQL将会在到达END语句时自动关闭它。

使用游标数据:

在一个游标被打开后,可以使用FETCH语句分别访问它的每一行。FETCH指定检索什么数据(所需的列),检索出来的数据存储在什么地方。它还向前移动游标中的内部指针,使下一条FETCH语句检索下一行(不重复读取同一行)。

循环检索数据,从第一行到最后一行:

  CREATE PROCEDURE processorders()

  BEGIN

    DECLARE done BOOLEAN DEFAULT 0;

    DECLARE o INT;

    DECLARE ordernumbers CURSOR

    FOR

    SELECT order_num FROM orders;

    DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;

    OPEN ordernumbers;

    

    REPEAT

      FETCH ordernumbers INTO o;

    UNTIL done END REPEAT;

    CLOSE ordernumbers;

  END;

REPEAT重复到条件为真(UNTIL done END REPEAT),此处的done为BOOLEAN条件,当done为真时打破重复。

DECLARE CONTINUE HANDLER声明了done设为1时的条件。CONTINUE HANDLER是在条件出现时被执行的代码。

3. 触发器

MySQL语句在需要时被执行,存储过程也是如此。但是,有时会想要某条语句(或某些语句)在事件发生时自动执行。

触发器:是MySQL响应以下任意语句而自动执行的一条MySQL语句(或位于BEGIN和END语句之间的一组语句):

  DELETE;INSERT;UPDATE。

其它MySQL语句不支持触发器。

创建触发器:

在创建触发器时,需要给出4条信息:

  唯一的触发器名;触发器关联的表;触发器应该响应的活动(DELETE、INSERT或UPDATE);触发器何时执行(处理之前或之后)。

触发器名必须在每个表中唯一,但不是在每个数据库中唯一。这表示同一数据库中的两个表可具有相同名字的触发器。

触发器用CREATE TRIGGER语句创建:

  CREATE TRIGGER newproduct AFTER INSERT ON products

  FOR EACH ROW SELECT 'Product added';

CREATE TRIGGER用来创建名为newproduct的新触发器。触发器可在一个操作发生之前或之后执行,这里给出AFTER INSERT,所以此触发器将在INSERT语句成功执行后执行。这个触发器还指定FOR EACH ROW,因此代码对每个插入行执行。在这个例子中,文本Product added将对每个插入的行显示一次。

只有表才支持触发器,视图不支持(临时表也不支持)。

触发器按每个表每个事件每次地定义,每个表每个事件每次只允许一个触发器。因此,每个表最多支持6个触发器(每条SELECT、UPDATE和DELETE的之前和之后)。单一触发器不能与多个事件或多个表关联,所以,如果需要一个对INSERT和UPDATE操作执行的触发器,则应该定义两个触发器。

触发器失败:如果BEFORE触发器失败,则MySQL将不执行请求的操作。如果BEFORE触发器或语句本身失败,MySQL将不执行AFTER触发器

删除触发器:

DROP TRIGGER语句:

  DROP TRIGGER newproduct;

触发器不能更新或覆盖,为了修改一个触发器,必须先删除它,然后再重新创建。

使用触发器:

INSERT触发器:在INSERT语句执行之前或之后执行。

  在INSERT触发器代码内,可引用一个名为NEW的虚拟表,访问被插入的行;

  在BEFORE INSERT触发器中,NEW中的值也可以被更新(允许更改被插入的值);

  对于AUTO_INCREMENT列,NEW在INSERT执行之前包含0,在INSERT执行之后包含新的自动生成值。

  

  CREATE TRIGGER neworder AFTER INSERT ON orders

  FOR EACH ROW SELECT NEW.order_num;

此代码创建一个名为neworder的触发器,它按照AFTER INSERT ON orders执行。FOR EACH ROW对于每一行,即每插入一行到表orders之后就执行SELECT NEW.order_num语句,这里的NEW指的是orders表。

DELETE触发器:

DELETE触发器在DELETE语句执行之前或之后执行。

  在DELETE触发器代码内,可以引用一个名为OLD的虚拟表,访问被删除的行;

  

  CREATE TRIGGER neworder AFTER DELETE ON orders

  FOR EACH ROW SELECT OLD.order_num;

UPDATE触发器:

  CREATE TRIGGER neworder AFTER UPDATE ON order FOR EACH ROW

  BEGIN

    ...

  END;

猜你喜欢

转载自www.cnblogs.com/cjj-ggboy/p/12543509.html