04MySQL的视图、存储过程和触发器
一、MySQL的视图
视图(view)是一个虚拟表,非真实存在,其本质是根据SQL语句获取动态的数据集,并为其命名,用户使用时只需使用视图名称即可获取结果集,并可以将其当作表来使用。数据库中只存放了视图的定义,而并没有存放视图中的数据。这些数据存放在原来的表中。使用视图查询数据时,数据库系统会从原来的表中取出对应的数据。因此,视图中的数据是依赖于原来的表中的数据的。一旦表中的数据发生改变,显示在视图中的数据也会发生改变。
视图的作用有
- 简化代码,可以把重复使用的查询封装成视图重复使用,同时可以使复杂的查询易于理解和使用。
- 安全原因,如果一张表中有很多数据,很多信息不希望让所有人看到,此时可以使用视图
1.1 视图的创建
创建视图的语法为
create [or replace] [algorithm = {undefined | merge | temptable}]
view view_name [(column_list)]
as select_statement
[with [cascaded | local] check option]
/*
参数说明:
(1)algorithm:可选项,表示视图选择的算法。
(2)view_name :表示要创建的视图名称。
(3)column_list:可选项,指定视图中各个属性的名词,默认情况下与SELECT语句中的查询的属性相同。
(4)select_statement:表示一个完整的查询语句,将查询记录导入视图中。
(5)[with [cascaded | local] check option]:可选项,表示更新视图时要保证在该视图的权限范围之内。
*/
1.2 修改视图
修改视图是指修改数据库中已存在的表的定义。当基本表的某些字段发生改变时,可以通过修改视图来保持视图和基本表之间一致。MySQL中通过CREATE OR REPLACE VIEW语句和ALTER VIEW语句来修改视图。
alter view 视图名 as select语句
1.3 更新视图
某些视图是可更新的。也就是说,可以在UPDATE、DELETE或INSERT等语句中使用它们,以更新基表的内容。对于可更新的视图,在视图中的行和基表中的行之间必须具有一对一的关系。如果视图包含下述结构中的任何一种,那么它就是不可更新的:
- 聚合函数(SUM(), MIN(), MAX(), COUNT()等)
- DISTINCT
- GROUP BY
- HAVING
- UNION或UNION ALL
- 位于选择列表中的子查询
- JOIN
- FROM子句中的不可更新视图
- WHERE子句中的子查询,引用FROM子句中的表。
- 仅引用文字值(在该情况下,没有要更新的基本表)
视图中虽然可以更新数据,但是有很多的限制。一般情况下,最好将视图作为查询数据的虚拟表,而不要通过视图更新数据。因为,使用视图更新数据时,如果没有全面考虑在视图中更新数据的限制,就可能会造成数据更新失败。
1.4 其他操作
- 重命名视图
-- rename table 视图名 to 新视图名;
rename table view1_emp to my_view1
- 删除视图
-- drop view 视图名[,视图名…];
drop view if exists view_student;
删除视图时,只能删除视图的定义,不会删除数据。
二、MySQL的存储过程
简单的说,存储过程就是一组SQL语句集,功能强大,可以实现一些比较复杂的逻辑功能,类似于JAVA语言中的方法;存储过就是数据库 SQL 语言层面的代码封装与重用。
存储过程的特性:
- 有输入输出参数,可以声明变量,有if/else, case,while等控制语句,通过编写存储过程,可以实现复杂的逻辑功能;
- 函数的普遍特性:模块化,封装,代码复用;
- 速度快,只有首次执行需经过编译和优化步骤,后续被调用可以直接执行,省去以上步骤;
2.1 存储过程的使用
其格式为
delimiter 自定义结束符号
create procedure 储存名([ in ,out ,inout ] 参数名 数据类形...)
begin
sql语句
end 自定义的结束符合
delimiter ;
-- 调用存储过程
call 储存名();
2.2 变量定义
2.2.1 局部变量
用户自定义,在begin/end块中有效
-- 声明变量
-- declare var_name type [default var_value];
declare nickname varchar(32);
-- 变量赋值
set nickname = ‘zhangsan’;
MySQL 中还可以使用 SELECT..INTO 语句为变量赋值。其基本语法如下:
select col_name [...] into var_name[,...]
from table_name wehre condition
/*
其中:
col_name 参数表示查询的字段名称;
var_name 参数是变量的名称;
table_name 参数指表的名称;
condition 参数指查询条件。
注意:当将查询结果赋值给变量时,该查询语句的返回结果只能是单行单列。
*/
2.2.2 用户变量
用户自定义,当前会话(连接)有效。类比java的成员变量 不需要提前声明,使用即声明
-- 语法:
@var_name
例如
delimiter $$
create procedure proc04()
begin
set @var_name01 = 'ZS';
end $$
delimiter;
call proc04() ;
2.2.3 系统变量
系统变量又分为全局变量与会话变量
- 全局变量在MYSQL启动的时候由服务器自动将它们初始化为默认值,这些默认值可以通过更改my.ini这个文件来更改。
- 会话变量在每次建立一个新的连接的时候,由MYSQL来初始化。MYSQL会将当前所有全局变量的值复制一份。来做为会话变量。
也就是说,如果在建立会话以后,没有手动更改过会话变量与全局变量的值,那所有这些变量的值都是一样的。全局变量与会话变量的区别就在于,对全局变量的修改会影响到整个服务器,但是对会话变量的修改,只会影响到当前的会话(也就是当前的数据库连接)。有些系统变量的值是可以利用语句来动态进行更改的,但是有些系统变量的值却是只读的,对于那些可以更改的系统变量,我们可以利用set语句进行更改。
全局变量的语法:
@@global.var_name
-- 查看全局变量
show global variables;
-- 查看某全局变量
select @@global.auto_increment_increment;
-- 修改全局变量的值
set global sort_buffer_size = 40000;
set @@global.sort_buffer_size = 40000;
会话变量的语法
@@session.var_name
-- 查看会话变量
show session variables;
-- 查看某会话变量
select @@session.auto_increment_increment;
-- 修改会话变量的值
set session sort_buffer_size = 50000;
set @@session.sort_buffer_size = 50000 ;
2.3 存储过程传参
-
in 表示传入的参数, 可以传入数值或者变量,即使传入变量,并不会更改变量的值,可以内部更改,仅仅作用在函数范围内。
-
out 表示从存储过程内部传值给调用者
-
inout 表示从外部传入的参数经过修改后可以返回的变量,既可以使用传入变量的值也可以修改变量的值(即使函数执行完)
2.4 流程控制
2.4.1 判断
IF语句包含多个条件判断,根据结果为TRUE、FALSE执行语句,与编程语言中的if、else if、else语法类似,其语法格式如下
-- 语法
if search_condition_1 then statement_list_1
[elseif search_condition_2 then statement_list_2] ...
[else statement_list_n]
end if
CASE是另一个条件判断的语句,类似于编程语言中的switch语法
-- 语法一(类比java的switch):
case case_value
when when_value then statement_list
[when when_value then statement_list] ...
[else statement_list]
end case
-- 语法二:
case
when search_condition then statement_list
[when search_condition then statement_list] ...
[else statement_list]
end case
2.4.2 循环
循环是一段在程序中只出现一次,但可能会连续运行多次的代码,循环中的代码会运行特定的次数,或者是运行到特定条件成立时结束循环
循环的类别包括
- while
- repeat
- loop
-- 类似于while
[标签:] while 循环条件 do
循环体;
end while[标签];
循环控制包括
- leave 类似于 break,跳出,结束当前所在的循环
- iterate类似于 continue,继续,结束本次循环,继续下一次
-- 类似于do while
[标签:] repeat
循环体;
until 条件表达式
end repeat [标签];
[标签:] loop
循环体;
if 条件表达式 then
leave [标签];
end if;
end loop;
2.5 游标
游标(cursor)是用来存储查询结果集的数据类型 , 在存储过程和函数中可以使用光标对结果集进行循环的处理。光标的使用包括光标的声明、OPEN、FETCH 和 CLOSE.
-- 声明语法
declare cursor_name cursor for select_statement
-- 打开语法
open cursor_name
-- 取值语法
fetch cursor_name into var_name [, var_name] ...
-- 关闭语法
close cursor_name
2.6 异常处理
MySql存储过程也提供了对异常处理的功能:通过定义HANDLER来完成异常声明的实现.
官方文档:https://dev.mysql.com/doc/refman/5.7/en/declare-handler.html
DECLARE handler_action HANDLER
FOR condition_value [, condition_value] ...
statement
/*
handler_action: {
CONTINUE -- 继续执行
| EXIT -- 退出程序
| UNDO -- 不支持,暂时不使用
}
condition_value: {
mysql_error_code -- MySQL的条件码
| condition_name -- MySQL的条件名
| SQLWARNING
| NOT FOUND
| SQLEXCEPTION
*/
在语法中,变量声明、游标声明、handler声明是必须按照先后顺序书写的,否则创建存储过程出错。
三、MySQL的存储函数
MySQL存储函数(自定义函数),函数一般用于计算和返回一个值,可以将经常需要使用的计算或功能写成一个函数。存储函数和存储过程一样,都是在数据库中定义一些 SQL 语句的集合。
存储函数与存储过程的区别在于
-
存储函数有且只有一个返回值,而存储过程可以有多个返回值,也可以没有返回值。
-
存储函数只能有输入参数,而且不能带in, 而存储过程可以有多个in,out,inout参数。
-
存储过程中的语句功能更强大,存储过程可以实现很复杂的业务逻辑,而函数有很多限制,如不能在函数中使用insert,update,delete,create等语句;
-
存储函数只完成查询的工作,可接受输入参数并返回一个结果,也就是函数实现的功能针对性比较强。
-
存储过程可以调用存储函数。但函数不能调用存储过程。
-
存储过程一般是作为一个独立的部分来执行(call调用)。而函数可以作为查询语句的一个部分来调用.
在MySQL中,创建存储函数使用create function关键字,其基本形式如下:
create function func_name ([param_name type[,...]])
returns type
[characteristic ...]
begin
routine_body
end;
/*
func_name :存储函数的名称。
param_name type:可选项,指定存储函数的参数。type参数用于指定存储函数的参数类型,该类型可以是MySQL数据库中所有支持的类型。
RETURNS type:指定返回值的类型。
characteristic:可选项,指定存储函数的特性。
routine_body:SQL代码内容。
*/
四、MySQL的触发器
触发器,就是一种特殊的存储过程。触发器和存储过程一样是一个能够完成特定功能、存储在数据库服务器上的SQL片段,但是触发器无需调用,当对数据库表中的数据执行DML操作时自动触发这个SQL片段的执行,无需手动条用。在MySQL中,只有执行insert,delete,update操作时才能触发触发器的执行,触发器的这种特性可以协助应用在数据库端确保数据的完整性 , 日志记录 , 数据校验等操作 。可以使用别名 OLD 和 NEW 来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。现在触发器还只支持行级触发,不支持语句级触发。
4.1 创建触发器
- 创建只有一个执行语句的触发器
create trigger 触发器名 before|after 触发事件
on 表名 for each row
执行语句;
- 创建有多个执行语句的触发器
create trigger 触发器名 before|after 触发事件
on 表名 for each row
begin
执行语句列表
end;
4.2 NEW与OLD
MySQL 中定义了 NEW 和 OLD,用来表示触发器的所在表中,触发了触发器的那一行数据,来引用触发器中发生变化的记录内容,具体地:
触发器类型 | 触发器类型NEW 和 OLD的使用 |
---|---|
INSERT 型触发器 | NEW 表示将要或者已经新增的数据 |
UPDATE 型触发器 | OLD 表示修改之前的数据 , NEW 表示将要或已经修改后的数据 |
DELETE 型触发器 | OLD 表示将要或者已经删除的数据 |
4.3 查看和删除触发器
- 查看触发器
show triggers;
- 删除触发器
-- drop trigger [if exists] trigger_name
drop trigger if exists trigger_test1;
MYSQL中触发器中不能对本表进行 insert ,update ,delete 操作,以免递归循环触发
尽量少使用触发器,假设触发器触发每次执行1s,insert table 500条数据,那么就需要触发500次触发器,光是触发器执行的时间就花费了500s,而insert 500条数据一共是1s,那么这个insert的效率就非常低了。
触发器是针对每一行的;对增删改非常频繁的表上切记不要使用触发器,因为它会非常消耗资源。