• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

MySQL入门(3)_mysql

mysql 搞代码 7年前 (2018-06-08) 111次浏览 已收录 0个评论
文章目录[隐藏]

mysql入门(三)

本学习笔记参考《MySQL必知必会》和官方手册MySQL 5.6 Reference Manual

MySQL入门(一)
MySQL入门(二)

本文内容:
– MySQL存储过程
– MySQL游标
– MySQL触发器

六、MySQL存储过程

6.1 什么是存储过程

简单来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。

6.2 使用存储过程

(1) 创建存储过程

mysql> DELIMITER  // mysql> CREATE PROCEDURE productpricing( )     -> BEGIN     -> SELECT Avg(prod_price) AS priceaverage     -> FROM products;     -> END  // Query OK, 0 rows affected (0.09 sec)  mysql> DELIMITER  ;

上面的语句创建了一个名为 productpricing 的存储过程,productpricing( ) 的括号里可以加入参数列表,BEGIN 和 END 之间为过程体。由于 MySQL 语句的分隔符为 ; ,而 mysql 命令行实用程序的分隔符也为 ; ,为了避免存储过程体里的 ; 不被 mysql 实用程序解释,解决办法是临时更改命令行实用程序的语句分隔符。DELIMITER // 语句重新定义分隔符为 // ,在创建完存储过程后再用 DELIMITER ; 把分隔符改回来。

(2) 使用存储过程

mysql> CALL productpricing( );

+————–+
| priceaverage |
+————–+
| 16.133571 |
+————–+

(3) 删除存储过程

存储过程在创建之后,就被保存在服务器上以供使用,直至被删除,删除命令如下:

mysql> DROP PROCEDURE productpricing;

注意:存储过程名后面没有括号。
如果指定要删除的存储过程存在则删除,如果不存在就会出错。为了使在不存在时也不至于出错可使用这样的语句:

mysql> DROP PROCEDURE IF EXISTS productpricing;

(4) 使用参数

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.07 sec)  mysql> DELIMITER ;

此存储过程接收3个参数:pl 存储产品的最低价格,ph 存储产品的最高价格,pa 存储产品的平均价格。每个参数必须有指定的类型,这里使用十进制。关键字 OUT 指出相应的参数用来从存储过程传出一个值(返回给调用者)。MySQL 支持 IN (传递给存储过程)、OUT (从存储过程传出)和 INOUT (对存储过程传入和传出)类型的参数。
调用这个存储过程:

mysql> CALL productpricing(@pricelow, @pricehigh, @priceaverage); Query OK, 1 row affected, 1 warning (0.04 sec)  mysql> SELECT @pricelow, @pricehigh, @priceaverage;

+———–+————+——————–+
| @pricelow | @pricehigh | @priceaverage |
+———–+————+——————–+
| 2.50 | 55.00 | 16.13 |
+———–+————+——————–+
所有 MySQL 变量都必须以 @ 开始。

另外一个例子:

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 //

onumber 定义为 IN ,因为订单号被传入存储过程。ototal 定义为 OUT ,因为要从存储过程返回合计。

mysql> CALL ordertotal(20005, @total); mysql> SELECT @total;

+——–+
| @total |
+——–+
| 149.87 |
+——–+

(5) 建立智能存储过程

-- create_procedure.sql -- Name: ordertotal -- Parameters: onumber = order number --             taxable = 0 if not taxable, 1 if taxable --             ototal  = order total variable DELIMITER  // 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;     -- And finally, save to out variable     SELECT total INTO ototal; END// DELIMITER  ;

此存储过程有很大的变动。首先,增加了注释(前面放置 –)。添加了另外一个参数 taxable,它是一个布尔值(如果要增加税则为真,否则为假)。在存储过程体中,用 DECLARE 语句定义了两个局部变量。DECLARE 要求指定变量名和数据类型,它也支持可选的默认值。
COMMENT 关键字是可选的,如果给出,将在 SHOW PROCEDURE STATUS 的结果中显示。

mysql> CALL ordertotal(20005, 0, @total); mysql> SELECT @total;

+——–+
| @total |
+——–+
| 149.87 |
+——–+

mysql> CALL ordertotal(20005, 0, @total); mysql> SELECT @total;

+——–+
| @total |
+——–+
| 158.86 |
+——–+

(6) 检查存储过程

检查创建存储过程的SQL语句:
SHOW CREATE PROCEDURE ordertotal;

如果想获得详细信息使用:
SHOW PROCEDURE STATUS; // 列出所有的存储过程的详细信息

可以使用 LIKE 起到过滤的作用:
SHOW PROCEDURE STATUS LIKE 'ordertotal';

七、MySQL游标

7.1 什么是游标

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

7.2 使用游标

步骤:
1) 在能够使用游标前,必须声明(定义)它,这个过程实际上没有检索数据,它只是定义要使用的 SELECT 语句。
2) 一旦声明后,必须打开游标以供使用。这个过程用前面定义的 SELECT 语句把数据实际检索出来。
3) 对于填有数据的游标,根据需要取出各行。
4)在结束游标使用时,必须关闭游标。

(1) 创建游标

-- create_cursor.sql DELIMITER  // CREATE  PROCEDURE  processorder( ) BEGIN     -- Declare the cursor     DECLARE  ordernumbers  CURSOR     FOR     SELECT  order_num  FROM  orders;      -- Open the cursor     OPEN  ordernumbers;      -- Close the cursor     CLOSE  ordernumbers; END// DELIMITER  ;

    MySQL中的游标只能用于存储过程,DECLARE 语句用来定义和命名游标,这里为 ordernumbers,在存储过程处理完成后,游标就会消失,因为它局限于存储过程。该存储过程只是打开和关闭了游标,并没有使用里面的数据。CLOSE 释放游标使用的内存资源,因此在每个游标不再需要时都应该关闭。如果你不明确关闭游标,MySQL 将会在到达END语句时自动关闭它。

(2) 使用游标

-- use_cursor.sql DELIMITER  // CREATE  PROCEDURE  processorder( ) BEGIN     -- Declare local variables     DECLARE  done  BOOLEAN  DEFAULT  0;     DECLARE  onumber INT ;     DECLARE  t  DECIMAL(8, 2);      -- Declare the cursor     DECLARE  ordernumbers  CURSOR     FOR     SELECT  order_num  FROM  orders;     -- Declare continue handler     DECLARE  CONTINUE  HANDLER  FOR  SQLSTATE  '02000'  SET  done = 1;      -- Create a table to store the results     CREATE  TABLE  IF  NOT  EXISTS  ordertotals         (order_num  INT, total  DECIMAL(8, 2));      -- Open the cursor     OPEN  ordernumbers;      -- Loop through all rows     REPEAT         -- Get order number         FETCH  ordernumbers  INTO  onumber;          -- Get the total for this order         CALL  ordertotal(onumber, 1, t);          -- Insert order and total into ordertotals         INSERT  INTO ordertotals(order_num, total)  VALUES(onumber, t);      -- End of loop     UNTIL  done  END  REPEAT;      -- Close the sursor     CLOSE  ordernumbers;  END// DELIMITER  ;

    在一个游标被打开后,可以使用 FETCH 语句分别访问它的每一行。FETCH 取出检索的数据同时它还向前移动游标中的内部行指针。该例子中的 FETCH 是在 REPEAT 内,因此它反复执行直到 done 为真(由 UNTIL done END REPEAT; 实现)。结束循环条件的语句为:
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
这条语句定义了一个 CONTINUE HANDLER,它是在条件出现时被执行的代码。这里,它指出当 SQLSTATE ‘02000’ 出现时,SET done = 1。SQLSTATE ‘02000’ 是一个未找到条件,当 REPEAT 由于没有更多的行共循环时,出现这个条件。
该存储过程,计算出每个订单号的带税的合计,并新建一个表,把这些数据插入到新建的表中。

mysql> source ./work/MySQL/use_cursor.sql; mysql> CALL  processorder( ); mysql> SELECT * FROM ordertotals;

+————+———–+
| order_num | total |
+————+———–+
| 20005 | 158.86 |
| 20009 | 40.78 |
| 20006 | 58.30 |
| 20007 | 1060.00 |
| 20008 | 132.50 |
| 20008 | 132.50 |
+————+———–+

八、MySQL触发器

8.1 什么是触发器

    如果你先让某些语句在事件发生时自动执行,就需要用到触发器。触发器是 MySQL 响应以下任意语句而自动执行的一条 MySQL 语句:
DELETE; INSERT; UPDATE;
其它MySQL语句不支持触发器。

8.2 创建触发器

mysql> CREATE TRIGGER newproduct AFTER INSERT ON ordertotals       >  FOR EACH ROW SELECT 'Product added' INTO @q;

创建触发器的语法:

CREATE     [DEFINER = { user | CURRENT_USER }]     TRIGGER trigger_name     trigger_time trigger_event     ON tbl_name FOR EACH ROW     trigger_body  trigger_time: { BEFORE | AFTER } trigger_event: { INSERT | UPDATE | DELETE }

注意:MySQL5.6 中的触发器不能返回结果集; 只有表支持触发器,视图和临时表都不支持。
这个触发器,在每次向表 ordertotals 插入数据时(对于每行)都会执行 SELECT ‘Product added’ INTO @q 。

8.3 删除触发器

mysql> DROP TRIGGER newproduct;

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

8.4 使用触发器

(1) INSERT触发器

    在 INSERT 触发器代码内,可引用一个名为 NEW 的虚拟表,访问被插入的行;
在 BEFORE INSERT 触发器中, NEW 中的值也可以被更新(允许更改将要被插入的值);
对于 AUTO_INCREMENT 列,NEW在 INSERT 之前包含0,在INSERT 之后包含新的自动生成值。

mysql> CREATE TRIGGER neworder AFTER INSERT ON orders                                   -> FOR EACH ROW SELECT NEW.order_num INTO @o_num;  mysql> INSERT INTO orders(order_date, cust_id)     -> VALUES(Now(), 10001);  mysql> SELECT @o_num;

+———-+
| @o_num |
+———-+
| 20010 |
+———-+

(2) DELETE触发器

    在 DELETE 触发器代码内,你可以引用一个名为 OLD 的虚拟表,访问被删除的行;
OLD 中的值全部都是只读的,不能更新;

mysql> DELIMITER // mysql> CREATE TRIGGER deletemytable BEFORE DELETE ON mytable     -> FOR EACH ROW     -> BEGIN     -> SELECT OLD.name INTO @n;     -> INSERT INTO mytable_new(name, myphone) VALUES(OLD.name, OLD.phone);     -> END//  mysql> DELETE FROM mytable WHERE name = 'Joy'; mysql> SELECT * FROM mytable_new;  mysql> SELECT @n;

+——+
| @n |
+——+
| Joy |
+——+
在触发器中使用 BEGIN END 块的好处是触发器能容纳多条SQL语句。

(3) UPDATE触发器

    在 UPDATE 触发器代码中,你可以引用一个名为 OLD 的虚拟表访问以前(UPDATE语句执行前)的值,引用一个名为 NEW 的虚拟表访问新更新的值;
在 BERFORE UPDATE 触发器中,NEW 中的值可能也被更新(允许更改将要用于UPDATE语句中的值);
OLD中的值全都是只读的,不能更新。

mysql> CREATE TRIGGER updatemytable BEFORE UPDATE ON mytable     -> FOR EACH ROW SET NEW.name = Upper(NEW.name);  mysql> UPDATE mytable SET name = 'John'  WHERE myid = 1004; mysql> SELECT name FROM mytable WHERE myid = 1004;

+——+
| name |
+——+
| JOHN |
+——+
早期版本(具体哪个版本开始可以不知)不允许在触发器代码中使用 CALL 调用存储过程,在 MySQL 5.6 中是可以的。

欢迎大家阅读《MySQL入门(3)_mysql》,跪求各位点评,by 搞代码


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:MySQL入门(3)_mysql

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址