视图、存储过程、存储函数、触发器
- 1.视图
- 1.1 介绍
- 1.2 语法
- 1.3 视图的检查选项
- 1.4 视图的更新
- 1.5 视图作用
- 1.6 案例
- 2.存储过程
- 21. 介绍
- 2.2 特点
- 2.3 语法
- 2.4 变量
- 2.4.1 系统变量
- 2.4.2用户自定义变量
- 2.4.3 局部变量
- 2.5参数
- 2.6条件语句
- 2.6.1 if 语法
- 2.6.2 case
- 2.7循环结构
- 2.7.1 WHILE循环
- 2.7.2 repeat循环
- 2.7.3 Loop循环
- 2.8游标
- 3.存储函数
- 4.触发器
- 4.1 介绍
- 4.2 语法
- 4.3 案例
- 总结:
1.视图
1.1 介绍
视图是一种虚拟存在的表。视图中的数据并不是数据库中实际存在的,行和列数据来自定义视图的查询中使用的表(基表),并且是在使用时动态生成的。
视图只保存了查询的SQL逻辑,不保存查询结果。所以在创建视图的时候,主要工作是创建SQL查询语句
1.2 语法
- 创建
CREATE [ OR REPLACE ] VIEW 视图名称[(列名列表)] AS SELECT语句 [WITH [ CASCADED
|LOCAL] CHECK OPTION ]
- 查询
查看创建视图语句:SHOW CREATE VIEW 视图名称;
查看视图数据:SELECT * FROM 视图名称…;
- 修改
方式一:CREATE [ OR REPLACE ] VIEW 视图名称[(列表的名称)] AS SELECT语句 [WITH [
CASCADED |LOCAL] CHECK OPTION ]
方式二:ALTER VIEW 视图名称[(列表的名称)] AS SELECT语句 [WITH [ CASCADED |LOCAL] CHECK OPTION ]
- 删除视图
DROP VIEW [IF EXISTS] 视图名称;
实例
--创建视图
create or replace view stu_v_1 as select id,name from student where id<=20;--查询视图
show create view stu_v_1;
SELECT * from stu_v_1;--修改视图
create or replace view as SELECT id ,name from student;--删除视图
drop view if EXISTS stu_v_1;
1.3 视图的检查选项
当使用WITH CHECK OPTION 子句创建视图时,MySQL会通过视图检查正在更改的每一行,例如 插入,更新,
-- 创建视图
create or replace view stu_v_1 as SELECT id ,name FROM student where id<=20;
-- 视图插入数据是在基表进行插入的
insert into stu_v_1 values(25,'tom');-- 创建视图
create or replace view stu_v_1 as SELECT id ,name FROM student where id<=20 with CASCADED check option; create or replace view stu_v_1 as SELECT id ,name FROM student where id<=20 with local check option;-- 修改视图
alter view stu_v_1 as select id,name from student where id<3;删除视图
drop view if exists stu_v_1 ;-- 查询视图
SELECT * from stu_v_1;
-- 创建视图 with cascade check option
create or replace view stu_v_1 as SELECT id ,name FROM student where id<=20;
insert into stu_v_1 values(25,'tom');#可以插入
create or replace view stu_v_2 as SELECT id ,name FROM stu_v_1 where id>10 with CASCADED check option; insert into stu_v_2 values(7,'tom');insert into stu_v_2 values(25,'tom');#报错,不可以插入,依赖的视图不满足条件insert into stu_v_2 values(15,'tom');create or replace view stu_v_3 as select id,name from stu_v_2 where id <=15;insert into stu_v_3 values(11,'tom');insert into stu_v_3 values(17,'tom');#可以插入,v3没有检查选项insert into stu_v_3 values(28,'tom');#不可以插入不满足v1
-- 创建视图 local check option create or replace view stu_v_4 as SELECT id ,name FROM stu_v_1 where id <=15;
insert into stu_v_4 values(7,'tom');#可以插入
insert into stu_v_4 values(16,'tom');#可以插入create or replace view stu_v_5 as SELECT id ,name FROM stu_v_4 where id>10 with local check option; insert into stu_v_5 values(13,'tom');#可以插入insert into stu_v_5 values (17,'tom');#可以插入 v4没有定义检查选项,不做检查create or replace view stu_v_6 as select id,name from stu_v_2 where id <=20;insert into stu_v_6 values(14,'tom');#可以插入insert into stu_v_3 values(18,'tom');#可以插入
1.4 视图的更新
1.5 视图作用
- 简单:
视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以定义为视图,不比每次指定条件。
- 安全:
数据库可以授权,但不能授权到数据库特定的行和列上。通过视图用户只能查询和修改制定的字段或数据
- 数据独立:
视图可以帮助用户屏蔽真实表结构变化带来的影响。
1.6 案例
--1.定义视图查指定的字段
create view tb_user_view as select id,name, profession,age,gender,status,CURRENT_DATE from tb_user ;SELECT * from tb_user_view;--2.将三表联查的sql创建为视图CREATE or replace view tb_stu_course_view as SELECT s.name student_name,s.no, c.name course_name from student s,student_course sc,course c where sc.studentid=s.id and sc.courseid=c.id;SELECT * from tb_stu_course_view;
2.存储过程
21. 介绍
多次网络请求,数据库层面将多条SQL语句封装,应用程序直接调用SQL集
2.2 特点
2.3 语法
- 创建
CREATE PROCEDURE 存储过程名称([参数列表])
BEGIN
–SQL语句
END;
- 调用
CALL 名称([参数]);
- 删除
DROP PROCEDURE [ IF EXISTS ]存储过程名称;
-- 存储过程基本语法
-- 创建存储过程
create procedure p1()
beginselect count(*) from student;
end;-- 调用> call p1();-- 查看存储过程select * from information_schema.ROUTINES where routine_schema='test';show create procedure p1;-- 删除
drop procedure if exists p1;
在命令行执行需要设置结束符
delimiter $$
-- 创建存储过程
create procedure p1()
beginselect count(*) from student;
end$$
2.4 变量
2.4.1 系统变量
系统变量: 是MySQL服务器提供的,不是用户自定义的,属于服务器层面。分为全局变量(GLOBAL)、会话变量(SESSION)。
- 查看系统变量
SHOW [ SESSION | GLOBAL ] VARIABLES; – 查看系统环境变量
SHOW [ SESSION | GLOBAL ] VARIABLES LIKE ‘…’; – 可以使用like模糊匹配查找变量
SHOW @@[SESSION | GLOBAL ] 系统变量名; – 查看指定变量的值
-- 查看系统变量
show variables;#默认sessionshow variables like 'auto%';show global variables like 'auto%';select @@session.autocommit;
- 设置系统变量
SET [GLOBAL | SESSION ] 系统变量名= 值;
SET @@[ SESSION | GLOBAL ] 系统变量名=值;
-- 设置系统变量
set session autocommit=1;set @@session.autocommit=0;
2.4.2用户自定义变量
用户定义变量:用户根据自己的需求自己定义变量,用户不用提前申明,在用的时候用“@变量名”使用就可以,其作用域当前连接会话。
- 赋值
set @var_name = expr [, @var_name = expr ]…;
set @var_name :=expr [,@var_name = expr ]…;SELECT @var_name = expr [, @var_name = expr ]…;
SELECT 字段名 INTO @var_name FROM 表名;
- 使用
SELECT @ var_name;
-- 自定义变量
set @myname :='test';
set @myage = 10;set @mygender :='男',@myhobby :='java';select @mycolor :='red';
SELECT count(*) into @mycount from tb_user;-- 使用
SELECT @myname,@myage,@mygender,@myhobby;SELECT @mycolor,@mycount;-- 注意用户自定义的变量不需要申明或者初始化,获取值为NULL
2.4.3 局部变量
局部变量:根据需要定义在局部生效的变量,访问之前,需要DECLARE 申明。可用作存储过程内的局部变量和输入参数,局部变量的范围是在其申明的BEGIN …END块。
- 声明
DECLARE 变量名 变量类型 [DEFAULT …];
变量类型就是数据类型:INT、BIGINT、CHAR、VARCAHR、DATE、TIME的等
- 赋值
SET 变量名= 值;
SET 变量名 :=值;
SELECT 字段名 INTO 变量名 FROM 表名 …;
-- 局部变量
-- 声明
-- 赋值
CREATE procedure p2()
begin declare stu_count int default 0;SELECT count(*) into stu_count from student;SELECT stu_count;
end;call p2();
2.5参数
用法:
CREATE PROCEDURE 存储过程名称([IN/OUT/INOUT 参数名 参数类型])
BEGIN
–SQL语句
END;
成绩等级
-- 存储过程为参数
CREATE procedure p4(IN score int ,OUT result varchar(10) )
beginif score >=85 thenset result :='优秀';elseif score >= 60 thenset result :='及格';elseset result :='不及格';end if;
end;
-- 将传出的参数给用户自定义参数
call p4(65,@result);
SELECT @result;
将传入的数据200转化为百分制
-- INOUTcreate PROCEDURE p5(INOUT score double)
beginset score :=score * 0.5;
end;set @score=198;
call p5(@score);
select @score;
2.6条件语句
2.6.1 if 语法
语法:
IF 条件1 THEN
…
ELSEIF 条件2 THEN – 可选
…
ELSE --可选
…
END IF;
判断分数等级
-- IF语法drop procedure if exists p3;
CREATE procedure p3()
begin declare score int default 58;declare result varchar(10);if score >=85 thenset result :='优秀';elseif score >= 60 thenset result :='及格';elseset result :='不及格';end if;SELECT result;end;call p3();
2.6.2 case
CASE case_value
WHEN when_value THEN statement_list
ELSE statement_list
END CASE;
根据传入的月份,判断季度
-- case
create procedure p6(in month int)
begindeclare result varchar(10);casewhen month>=1 and month <=3 then set result :='第一季度';when month>=4 and month <=6 then set result :='第二季度';when month>=7 and month <=9 then set result :='第三季度';when month>=10 and month <=12 then set result :='第四季度'; else set result :='非法函数';end case;SELECT concat('输入月份:',month,'季度为:',result);
end;call p6(16);
2.7循环结构
2.7.1 WHILE循环
当while循环是有条件的循环控制语句,当条件满足后,执行循环体的SQL语句
语法:
先判断条件,如果为true,则执行逻辑,否则,不执行逻辑
WHILE search_condition DO
SQL逻辑;
END WHILE;
while从1到n累加
-- while
-- 第一种
drop procedure if exists p7;
create procedure p7(IN n int )
begindeclare i int default 1;declare sum int default 0;WHILE i <=n DOset sum := sum +i;set i := i +1;END WHILE;select sum;
end;
call p7(5);-- 第2种
drop procedure if exists p7;
create procedure p7(IN n int )
begindeclare sum int default 0;WHILE n>0 DOset sum := sum +n;set n := n -1;END WHILE;select sum;
end;call p7(100);
2.7.2 repeat循环
REPEAT
statement_list
UNTIL search_condition
END REPEAT;
累加
-- repeat
drop procedure if exists p8;
create procedure p8(IN n int )
begindeclare sum int default 0;REPEATset sum :=sum + n;set n := n -1;UNTIL n<=0 END REPEAT;
select sum;
end;call p8(100);
2.7.3 Loop循环
LOOP实现简单循环,如果不在SQL逻辑中增加退出循环条件,可以用来实现简单死循环。loop可以配合两个语句使用
- LEAVE:配合循环使用,退出循环。
- ITERATE:必须用在循环中,作用是跳出当前循环剩下的语句,直接进入下一个循环
loop循环的基本格式:
[loop_label:] LOOP
loop循环语句
end loop [loop_label];
LEAVE label; – 退出指定标记的循环体
ITERATE label; – 直接进入下一次循环
-- loopcreate procedure p9(IN n int )
beginDECLARE sum int default 0;s:loopif n<=0 thenleave s;end if;set sum := sum + n;set n := n - 1;end loop s;SELECT sum;
end;call p9(100);
2.8游标
游标(CURSOR) 是用来存储结果集的数据类型,在存储过程和函数中可以使用游标对结果集进行循环的处理。游标的使用包括游标的声明、open、fetch、close;语法如下:
- 声明游标
DECLARE 游标名称 CURSOR FOR 查询语句;
- 打开游标
OPEN 游标名称;
- 获取游标
FETCH 游标名称 INTO 变量[,变量];
-关闭游标
CLOSE 游标名称;
- 条件处理程序
-- 声明游标 存储结果集
-- 准备 创建表结构
-- 开启游标
-- 获取游标的记录
-- 插入数据到新表
-- 关闭游标create procedure p11(in uage int)
begindeclare uname varchar(100);DECLARE ujob varchar(100);declare u_cursor CURSOR FOR select name ,job from emp where age<=uage;-- 当状态码为02000 结束游标declare exit handler for SQLSTATE '02000' close u_cursor;-- declare exit handler for not found close u_cursor;drop table if exists emp_pro;create table if not exists emp_pro(id int primary key auto_increment,name VARCHAR(100),job varchar(100));open u_cursor;-- 循环获取游标的数据 死循环while true do fetch u_cursor into uname,ujob;insert into emp_pro values(null,uname,ujob);end while;close u_cursor;end;call p11(23);
3.存储函数
存储函数:是有返回值的存储过程,存储函数的参数只能是IN类型的,具体语法:
CREATE FUNCTION 存储函数名称([参数列表])
RETURNS type [characteristic …]
BEGIN
– SQL语句
RETURN …;
END;
characteristic:说明
DETERMINISTIC:相同的输入参数总是产生相同的结果
NO SQL:不包含SQL语句
READS SQL DATA:包含读取数据的语句,但不包含写入的语句
determinstic
确定性的意思,确定性的意思是,对于相同的输入参数,函数或存储过程总是返回相同的结果。这样的函数或存储过程在查询优化和缓存中具有更高的效率,因为查询优化器可以根据输入参数进行缓存和重用计算结果。如果将存储过程或函数声明为DETERMINISTIC,则MySQL会假定它是确定性的,并且会对其进行优化。如果不声明为DETERMINISTIC,MySQL会假定该存储过程或函数是非确定性的,并且在每次调用时都会重新计算结果。
因此,使用DETERMINISTIC属性可以提高查询的性能和效率。
-- 存储函数
CREATE FUNCTION fun1(n int)
RETURNS int DETERMINISTIC
BEGINdeclare sum int DEFAULT 0;WHILE n>0 DOset sum :=sum + n;set n :=n -1;END WHILE;RETURN sum;
END;SELECT fun1(100);
4.触发器
4.1 介绍
4.2 语法
创建
CREATE TRIGGER trigger_name
BEFORE/AFTER INSERT/UPDATE/DELETE
ON tbl_name for EACH ROW – 行级触发器
BEGIN
trigger_stmt;
END;
查看
SHOW TRIGGERS;
删除
DROP TRIGGER [schema_name.]trigger_name;
4.3 案例
通过触发器记录表的数据变更,将变更日志插入到日志表log表中
准备数据
-- 触发器
CREATE TRIGGER trigger_name
BEFORE/AFTER INSERT/UPDATE/DELETE
ON tbl_name for EACH ROW -- 行级触发器
BEGINtrigger_stmt;
END;
-- 查看触发器
SHOW TRIGGERS;
-- 删除触发器
DROP TRIGGER trigger_name;-- 创建日志表,在进行insert之后写入日志
create table emp_log(id int(11) not null auto_increment,operation varchar(20) not null comment '操作类型insert、update、delete',operation_time datetime not null comment '操作时间',operation_id int not null comment '操作ID',operation_params varchar(500),primary key(id)
)engine=innodb DEFAULT CHARSET=utf8;
插入数据触发器
-- 插入数据触发器
CREATE trigger emp_triggerafter insert on emp for each row
BEGINinsert into emp_log values(null,'insert',now(),new.id,CONCAT('操作的id:',new.id,'操作的name:',new.name,'操作的年龄:',new.age,'job:',new.job));
END;-- 查看触发器
show triggers;
-- 删除触发器
drop trigger emp_trigger;-- 插入数据,查看触发器操作
INSERT INTO `itcast`.`emp`(`id`, `name`, `age`, `job`, `salary`, `entrydate`, `managerid`, `dept_id`) VALUES (16, 'hahaha', 23, '市场', 12500, '2005-09-07', 1, 3);
修改数据触发器
-- 修改数据的触发器
CREATE trigger emp_update_triggerafter update on emp for each row
BEGINinsert into emp_log values(null,'update',now(),new.id,CONCAT('更新之前数据操作的id:',old.id,'操作的name:',old.name,'操作的年龄:',old.age,'job:',old.job,'|更新之后数据操作的id:',new.id,'操作的name:',new.name,'操作的年龄:',new.age,'job:',new.job));
END;
drop trigger emp_update_trigger;
UPDATE `itcast`.`emp` SET `age` = 99, WHERE `id` = 16;
删除数据的触发器
-- 删除数据的触发器
CREATE trigger emp_delete_triggerafter delete on emp for each row
BEGINinsert into emp_log values(null,'delete',now(),old.id,CONCAT('删除之前数据操作的id:',old.id,'操作的name:',old.name,'操作的年龄:',old.age,'job:',old.job));
END;