zoukankan      html  css  js  c++  java
  • 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;

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

    查看所有的存储过程:

    show procedure status;

    查看存储过程结构:

    show create procedure procname;

    存储过程使用参数:

    变量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;

  • 相关阅读:
    wmi
    Python中基本同步原语的使用
    Python多线程的几种实现方式
    TCP/IP详解 卷1 第一章 概述
    对利用sqlmap获取os-shell过程的一次抓包分析
    12.19 Aggregate (GROUP BY) Functions
    13.2.9 SELECT 语法
    GitHack 源码分析
    CTF遇到的问题-长期更新
    在Windows server2008中搭建sqli-lab实验环境
  • 原文地址:https://www.cnblogs.com/cjj-ggboy/p/12543509.html
Copyright © 2011-2022 走看看