Linux——MySQL存储和触发器

一、存储

PS:存储过程是数据库存储的一个重要的功能,但是 MySQL 在 5.0 以前并不支持存储过程,这使得 MySQL 在应用上大打折扣。好在 MySQL 5.0 终于开始已经支持存储过程,这样即可以大大提高数据库的处理速度,同时也可以提高数据库编程的灵活性。

1.存储概述

  • 存储过程是一组为了完成特定功能的SQL语句集合。使用存储过程的目的就是将常用或复杂的工作预先用SQL语句写好并用一个指定名称存储起来,这个过程编译和优化后存储在数据库服务器中,因此称为存储过程。当以后需要数据库提供与定义好的存储过程的功能相同的服务时,只需要调用“CALL 存储过程名称”即可使用相应的功能!
  • 操作数据库的 SQL 语句在执行的时候需要先编译,然后执行。存储过程则采用另一种方式来执行 SQL 语句。
  • 一个存储过程是一个可编程的函数,它在数据库中创建并保存,一般由SQL语句和一些特殊的控制结构组成!当希望在不同的应用程序或平台上执行相应的特定功能时,存储过程就变得尤为合适!

2.存储优点

  • 封装性 存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的 SQL 语句,并且数据库专业人员可以随时对存储过程进行修改,而不会影响到调用它的应用程序源代码。
  • 可增强 SQL 语句的功能和灵活性 存储过程可以用流程控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。
  • 可减少网络流量 由于存储过程是在服务器端运行的,且执行速度快,因此当客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而可降低网络负载。
  • 高性能 存储过程执行一次后,产生的二进制代码就驻留在缓冲区,在以后的调用中,只需要从缓冲区中执行二进制代码即可,从而提高了系统的效率和性能。
  • 提高数据库的安全性和数据的完整性 使用存储过程可以完成所有数据库操作,并且可以通过编程的方式控制数据库信息访问的权限。

3.存储过程创建语法

mysql> delimiter ??  #更改其默认的分隔符为“??”,也可以是其他任意符号,只要不是默认的“;”就行
mysql> create  procedure name() #定义存储过程name
    -> begin #存储过程开始
    -> ……  #存放的可以是一些sql语句的集合,当然,它同样有一些判断、循环等语句!!!
    -> end ?? #存储过程结束

mysql> delimiter ;   #更改为默认的分割符,注意中间必须有空格!!!
mysql> call name();  #调用刚才定义的name存储过程

1. 自定义存储过程

1.1先插入表

mysql> create database cunchu;
Query OK, 1 row affected (0.00 sec)

mysql> use cunchu;
Database changed
mysql> create table roster
    -> (
    -> id int,
    -> name varchar(20),
    -> sex varchar(20),
    -> scores float
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> insert into roster
    -> values 
    -> (1,'张三','男',90.5),
    -> (2,'李四','男',85.5),
    -> (3,'王五','女',78.5),
    -> (4,'刘三','女',66.5),
    -> (5,'赵四','男',50.5);
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> select * from roster;
+------+--------+------+--------+
| id   | name   | sex  | scores |
+------+--------+------+--------+
|    1 | 张三   | 男   |   90.5 |
|    2 | 李四   | 男   |   85.5 |
|    3 | 王五   | 女   |   78.5 |
|    4 | 刘三   | 女   |   66.5 |
|    5 | 赵四   | 男   |   50.5 |
+------+--------+------+--------+
5 rows in set (0.00 sec)

1.2 编写存储过程

以下例子为查看花名册中的所有数据!!!

mysql> delimiter !!
mysql> create procedure test1()
    -> begin
    -> select * from roster;   #查询roster表内容
    -> end !!
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;
mysql> call test1();
+------+--------+------+--------+
| id   | name   | sex  | scores |
+------+--------+------+--------+
|    1 | 张三   | 男   |   90.5 |
|    2 | 李四   | 男   |   85.5 |
|    3 | 王五   | 女   |   78.5 |
|    4 | 刘三   | 女   |   66.5 |
|    5 | 赵四   | 男   |   50.5 |
+------+--------+------+--------+
5 rows in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

2. while语句的存储过程

以下例子为从1+2+3+4……+100 等于多少!!!

mysql> delimiter @@  

mysql> create procedure test2()
    -> begin 
    -> declare i int; 			 #定义i为变量名称
    -> declare summary int;  	 #定义summary为变量名称
    -> set i=1;					 #设置变量的初始值为1
    -> set summary=0;			 #设置变量的初始值为0
    -> while i<=100  			 #当i小于或等于100时,执行以下操作
    -> do			 
    -> set summary=summary+i;
    -> set i=i+1;
    -> end while ;				 #循环结束
    -> select summary;			 #查询summary的值
    -> end @@
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;
mysql> call test2();
+---------+
| summary |
+---------+
|    5050 |
+---------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

3. if判断语句的存储过程

以下例子为查找花名册中为男性的学生!!!

mysql> delimiter @@
mysql> create procedure test3(in t char)
    -> begin
    -> if t="男" then  						 #if语句定义t为男
    -> select * from roster where sex="男";   #查询roster中sex为男
    -> else
    -> select * from roster where sex="女";	 #查询roster中sex为女
    -> end if;  							  #if语句结束
    -> end @@
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;
mysql> call test3("男");
+------+--------+------+--------+
| id   | name   | sex  | scores |
+------+--------+------+--------+
|    1 | 张三   | 男   |   90.5 |
|    2 | 李四   | 男   |   85.5 |
|    5 | 赵四   | 男   |   50.5 |
+------+--------+------+--------+
3 rows in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> call test3("女");
+------+--------+------+--------+
| id   | name   | sex  | scores |
+------+--------+------+--------+
|    3 | 王五   | 女   |   78.5 |
|    4 | 刘三   | 女   |   66.5 |
+------+--------+------+--------+
2 rows in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

4. case语句的存储过程

以下例子为查找花名册中的成绩!!!

mysql> delimiter @@
mysql> create procedure test4(in t int)
    -> begin
    -> case t												  
    -> when 1 then
    -> select * from roster where scores>90;                  #查询roster表中scores为大于90
    -> when 2 then
    -> select * from roster where scores>80 and scores<=90;	  #查询roster表中scores为大于80和小于90
    -> when 3 then
    -> select * from roster where scores>60 and scores<=80;	  #查询roster表中scores为大于90和小于80
    -> when 4 then 
    -> select * from roster where scores<60;  				  #查询roster表中scores为小于60
    -> else
    -> select * from roster;								  #查询结果无则执行这条命令
    -> end case;                                         
    -> end @@
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;
mysql> call test4(1);
+------+--------+------+--------+
| id   | name   | sex  | scores |
+------+--------+------+--------+
|    1 | 张三   | 男   |   90.5 |
+------+--------+------+--------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> call test4(2);
+------+--------+------+--------+
| id   | name   | sex  | scores |
+------+--------+------+--------+
|    2 | 李四   | 男   |   85.5 |
+------+--------+------+--------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> call test4(3);
+------+--------+------+--------+
| id   | name   | sex  | scores |
+------+--------+------+--------+
|    3 | 王五   | 女   |   78.5 |
|    4 | 刘三   | 女   |   66.5 |
+------+--------+------+--------+
2 rows in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> call test4(4);
+------+--------+------+--------+
| id   | name   | sex  | scores |
+------+--------+------+--------+
|    5 | 赵四   | 男   |   50.5 |
+------+--------+------+--------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> call test4(5);
+------+--------+------+--------+
| id   | name   | sex  | scores |
+------+--------+------+--------+
|    1 | 张三   | 男   |   90.5 |
|    2 | 李四   | 男   |   85.5 |
|    3 | 王五   | 女   |   78.5 |
|    4 | 刘三   | 女   |   66.5 |
|    5 | 赵四   | 男   |   50.5 |
+------+--------+------+--------+
5 rows in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

5. 修改存储过程

语法:

mysql> help alter procedure
Name: 'ALTER PROCEDURE'
Description:
Syntax:
ALTER PROCEDURE proc_name [characteristic ...]

characteristic: {
    COMMENT 'string'
  | LANGUAGE SQL
  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  #      包含SQL      没有sql   读取SQL数据        修改SQL数据
  | SQL SECURITY { DEFINER | INVOKER }
  #                 定义者  | 调用程序
}

修改存储过程roster的定义,将读写权限改为 MODIFIES SQL DATA,并指明调用者可以执行

mysql> alter procedure test1  MODIFIES SQL DATA  SQL SECURITY INVOKER;
Query OK, 0 rows affected (0.00 sec)

mysql> show create procedure test1\G;
*************************** 1. row ***************************
           Procedure: test1
            sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
    Create Procedure: CREATE DEFINER=`root`@`localhost` PROCEDURE `test1`()
    MODIFIES SQL DATA
    SQL SECURITY INVOKER
begin
select * from roster;
end
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci
1 row in set (0.00 sec)

6. 删除存储

  • 过程名 指定要删除的存储过程的名称。
  • IF EXISTS 指定这个关键字,用于防止因删除不存在的存储过程而引发的错误。 注意:存储过程名称后面没有参数列表,也没有括号,在删除之前,必须确认该存储过程没有任何依赖关系,否则会导致其他与之关联的存储过程无法运行。
mysql> drop procedure if exists test1;
Query OK, 0 rows affected (0.00 sec)

mysql> call test1();
ERROR 1305 (42000): PROCEDURE cunchu.test1 does not exist

二、触发器

1.概述

MySQL 数据库中触发器是一个特殊的存储过程,不同的是执行存储过程要使用 CALL 语句来调用,而触发器的执行不需要使用 CALL 语句来调用,也不需要手工启动,只要一个预定义的事件发生就会被 MySQL自动调用。

2.触发器的优点

  • 触发程序的执行是自动的,当对触发程序相关表的数据做出相应的修改后立即执行。
  • 触发程序可以通过数据库中相关的表层叠修改另外的表。
  • 触发程序可以实施比 FOREIGN KEY 约束、CHECK 约束更为复杂的检查和操作。

3.触发器的作用

触发器与表关系密切,主要用于保护表中的数据。特别是当有多个表具有一定的相互联系的时候,触发器能够让不同的表保持数据的一致性。只有执行 INSERT、UPDATE 和 DELETE 操作时才能激活触发器。

4.MySQL 所支持的触发器有

INSERT 触发器

  • 在 INSERT 触发器代码内,可引用一个名为 NEW(不区分大小写)的虚拟表来访问被插入的行。
  • 在 BEFORE INSERT 触发器中,NEW 中的值也可以被更新,即允许更改被插入的值(只要具有对应的操作权限)。
  • 对于 AUTO_INCREMENT 列,NEW 在 INSERT 执行之前包含的值是 0,在 INSERT 执行之后将包含新的自动生成值。

UPDATE 触发器

  • 在 UPDATE 触发器代码内,可引用一个名为 NEW(不区分大小写)的虚拟表来访问更新的值。
  • 在 UPDATE 触发器代码内,可引用一个名为 OLD(不区分大小写)的虚拟表来访问 UPDATE 语句执行前的值。
  • 在 BEFORE UPDATE 触发器中,NEW 中的值可能也被更新,即允许更改将要用于 UPDATE 语句中的值(只要具有对应的操作权限)。 OLD 中的值全部是只读的,不能被更新。 注意:当触发器设计对触发表自身的更新操作时,只能使用 BEFORE 类型的触发器,AFTER 类型的触发器将不被允许。

DELETE 触发器

  • 在 DELETE 触发器代码内,可以引用一个名为 OLD(不区分大小写)的虚拟表来访问被删除的行。 OLD 中的值全部是只l读的,不能被更新。

5.触发器使用的过程中,MySQL 会按照以下方式来处理错误

  • 若对于事务性表,如果触发程序失败,以及由此导致的整个语句失败,那么该语句所执行的所有更改将回滚;对于非事务性表,则不能执行此类回滚,即使语句失败,失败之前所做的任何更改依然有效。
  • 若 BEFORE 触发程序失败,则 MySQL 将不执行相应行上的操作。
  • 若在 BEFORE 或 AFTER 触发程序的执行过程中出现错误,则将导致调用触发程序的整个语句失败。
  • 仅当 BEFORE 触发程序和行操作均已被成功执行,MySQL 才会执行AFTER触发程序。

创建触发器语法:

查看帮助

mysql> help create trigger
Name: 'CREATE TRIGGER'
Description:
Syntax:
CREATE
    [DEFINER = user]
    TRIGGER trigger_name
    trigger_time trigger_event
    ON tbl_name FOR EACH ROW
    [trigger_order]
    trigger_body

trigger_time: { BEFORE | AFTER }
 #                 之前 | 之后
trigger_event: { INSERT | UPDATE | DELETE }

trigger_order: { FOLLOWS | PRECEDES } other_trigger_name

语法:

mysql> delimiter $$           #更改其默认的分隔符为“$$”,也可以是其他任意符号,只要不是默认的“;”就行
mysql> create trigger test    #为触发器定义名字为test
    -> after insert           #选择after
    -> on 表名 for each row
    -> begin                  #开启
    -> ……                     #自定义sql语句
    -> end $$				  #结束
    
mysql> delimiter ;			  #更改为默认的分割符,注意中间必须有空格!!!	

1.创建表并插入数据

mysql> create table goods
    -> ( 
    -> g_id int,
    -> g_name varchar(30),
    -> quantity int 
    -> );
Query OK, 0 rows affected (0.08 sec)

mysql> create table orders 
    -> (
    -> o_id int ,
    -> g_id int,
    -> counts int,
    -> price int
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> insert into goods
    -> values 
    -> (1,'apple','100'),
    -> (2,'banana','100'),
    -> (3,'pineapple','100');
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from goods;
+------+-----------+----------+
| g_id | g_name    | quantity |
+------+-----------+----------+
|    1 | apple     |      100 |
|    2 | banana    |      100 |
|    3 | pineapple |      100 |
+------+-----------+----------+
3 rows in set (0.00 sec)

2.insert语句

以下例子为商品卖出后库存表自动减去相对应的商品!!!

mysql> delimiter $$ 
mysql> create trigger test5
    -> after insert 
    -> on orders for each row
    -> begin
    -> update goods set quantity=quantity-new.counts where g_id=new.g_id;
    -> end $$
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;

#查看原先数据
mysql> select * from goods;
+------+-----------+----------+
| g_id | g_name    | quantity |
+------+-----------+----------+
|    1 | apple     |      100 |
|    2 | banana    |      100 |
|    3 | pineapple |      100 |
+------+-----------+----------+
3 rows in set (0.00 sec)

#插入数据
mysql> insert into orders values(1,2,10,55);
Query OK, 1 row affected (0.00 sec)

#查看插入之后的对应数据是否对应
mysql> select * from orders;
+------+------+--------+-------+
| o_id | g_id | counts | price |
+------+------+--------+-------+
|    1 |    2 |     10 |    55 |
+------+------+--------+-------+
1 row in set (0.00 sec)

mysql> select * from goods;
+------+-----------+----------+
| g_id | g_name    | quantity |
+------+-----------+----------+
|    1 | apple     |      100 |
|    2 | banana    |       90 |
|    3 | pineapple |      100 |
+------+-----------+----------+
3 rows in set (0.00 sec)

3.update语句

mysql> delimiter $$
mysql> create trigger test6
    -> after update 
    -> on orders for each row
    -> begin
    -> update goods set quantity=quantity-(new.counts-old.counts) where g_id=new.g_id;
    -> end $$
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;

3.2 增加

以下为客户吧订单加大,库存表自动变化!!!

#查看俩个表的数据
mysql> select * from goods;    
+------+-----------+----------+
| g_id | g_name    | quantity |
+------+-----------+----------+
|    1 | apple     |      100 |
|    2 | banana    |       90 |
|    3 | pineapple |      100 |
+------+-----------+----------+
3 rows in set (0.00 sec)

mysql> select * from orders;
+------+------+--------+-------+
| o_id | g_id | counts | price |
+------+------+--------+-------+
|    1 |    2 |     10 |    55 |
+------+------+--------+-------+
1 row in set (0.00 sec)

#更新数据
mysql> update orders set counts=20 where o_id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

#查看更新之后的俩表的数据
mysql> select * from orders;
+------+------+--------+-------+
| o_id | g_id | counts | price |
+------+------+--------+-------+
|    1 |    2 |     20 |    55 |
+------+------+--------+-------+
1 row in set (0.00 sec)

mysql> select * from goods;
+------+-----------+----------+
| g_id | g_name    | quantity |
+------+-----------+----------+
|    1 | apple     |      100 |
|    2 | banana    |       80 |
|    3 | pineapple |      100 |
+------+-----------+----------+
3 rows in set (0.00 sec)

3.3 减少

以下为客户退货之后库存自动变化为实时数据!!!

#更改数据
mysql> update orders set counts =5 where o_id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

#查看更改之后的数据
mysql> select * from orders;
+------+------+--------+-------+
| o_id | g_id | counts | price |
+------+------+--------+-------+
|    1 |    2 |      5 |    55 |
+------+------+--------+-------+
1 row in set (0.00 sec)

mysql> select * from goods;
+------+-----------+----------+
| g_id | g_name    | quantity |
+------+-----------+----------+
|    1 | apple     |      100 |
|    2 | banana    |       95 |
|    3 | pineapple |      100 |
+------+-----------+----------+
3 rows in set (0.00 sec)

4.delete语句

以下为客户退货之后表内自动转换相对应的数据!!!

mysql> delimiter $$
mysql> create trigger test7
    -> after delete
    -> on orders for each row 
    -> begin
    -> update goods set quantity=quantity+old.counts where g_id=old.g_id;
    -> end $$
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;

#查看原先数据
mysql> select * from orders;
+------+------+--------+-------+
| o_id | g_id | counts | price |
+------+------+--------+-------+
|    1 |    2 |      5 |    55 |
+------+------+--------+-------+
1 row in set (0.00 sec)

mysql> select * from goods;
+------+-----------+----------+
| g_id | g_name    | quantity |
+------+-----------+----------+
|    1 | apple     |      100 |
|    2 | banana    |       95 |
|    3 | pineapple |      100 |
+------+-----------+----------+
3 rows in set (0.00 sec)

#删除出货表的数据
mysql> delete from orders where o_id =1;
Query OK, 1 row affected (0.01 sec)

#查看删除之后的对应数据
mysql> select * from orders;
Empty set (0.00 sec)

mysql> select * from goods;
+------+-----------+----------+
| g_id | g_name    | quantity |
+------+-----------+----------+
|    1 | apple     |      100 |
|    2 | banana    |      100 |
|    3 | pineapple |      100 |
+------+-----------+----------+
3 rows in set (0.00 sec)

5.删除触发器

#查看触发器
mysql> show create trigger test7\G
*************************** 1. row ***************************
               Trigger: test7
              sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
SQL Original Statement: CREATE DEFINER=`root`@`localhost` trigger test7
after delete
on orders for each row 
begin
update goods set quantity=quantity+old.counts where g_id=old.g_id;

end
  character_set_client: utf8
  collation_connection: utf8_general_ci
    Database Collation: utf8_general_ci
               Created: 2020-12-27 20:40:01.82
1 row in set (0.00 sec)

#删除触发器
mysql> drop trigger test7;
Query OK, 0 rows affected (0.00 sec)

mysql> show create trigger test7\G
ERROR 1360 (HY000): Trigger does not exist

猜你喜欢

转载自blog.csdn.net/weixin_45191791/article/details/112251721