diff --git a/Day36-40/36-38.关系型数据库MySQL.md b/Day36-40/36-38.关系型数据库MySQL.md index 81f870c..434718e 100644 --- a/Day36-40/36-38.关系型数据库MySQL.md +++ b/Day36-40/36-38.关系型数据库MySQL.md @@ -431,9 +431,113 @@ #### 视图 -#### 索引 +视图是关系型数据库中将一组查询指令构成的结果集组合成可查询的数据表的对象。简单的说,视图就是虚拟的表,但与数据表不同的是,数据表是一种实体结构,而视图是一种虚拟结构,你也可以将视图理解为保存在数据库中被赋予名字的SQL语句。 -#### 过程 +使用视图可以获得以下好处: + +1. 可以将实体数据表隐藏起来,让外部程序无法得知实际的数据结构,让访问者可以使用表的组成部分而不是整个表,降低数据库被攻击的风险。 +2. 在大多数的情况下视图是只读的(更新视图的操作通常都有诸多的限制),外部程序无法直接透过视图修改数据。 +3. 重用SQL语句,将高度复杂的查询包装在视图表中,直接访问该视图即可取出需要的数据;也可以将视图视为数据表进行连接查询。 +4. 视图可以返回与实体数据表不同格式的数据, + +创建视图。 + +```SQL +create view vw_avg_score +as + select stuname, avgscore + from + tb_student t1, + (select sid, round(avg(score), 1) as avgscore from tb_record group by sid) t2 + where stuid=sid; +``` + +> **提示**:因为视图不包含数据,所以每次使用视图时,都必须执行查询以获得数据,如果你使用了连接查询、嵌套查询创建了较为复杂的视图,你可能会发现查询性能下降得很厉害。因此,在使用复杂的视图前,应该进行测试以确保其性能能够满足应用的需求。 + +使用视图。 + +```SQL +select stuname, avgscore from vw_avg_score order by avgscore desc; +``` + +``` ++--------------+----------+ +| stuname | avgscore | ++--------------+----------+ +| 杨过 | 95.6 | +| 任我行 | 53.5 | +| 王语嫣 | 84.3 | +| 纪嫣然 | 73.8 | +| 岳不群 | 78.0 | +| 东方不败 | 88.0 | +| 项少龙 | 92.0 | ++--------------+----------+ +``` + +删除视图。 + +```SQL +drop view vw_avg_score; +``` + +> **说明**:如果希望更新视图,可以先用上面的命令删除视图,也可以通过`create or replace view`来更新视图。 + +视图的规则和限制。 + +1. 视图可以嵌套,可以利用从其他视图中检索的数据来构造一个新的视图。视图也可以和表一起使用。 +2. 创建视图时可以使用`order by`子句,但如果从视图中检索数据时也使用了`order by`,那么该视图中原先的`order by`会被覆盖。 +3. 视图无法使用索引,也不会激发触发器(实际开发中因为性能等各方面的考虑,通常不建议使用触发器,所以我们也不对这个概念进行介绍)的执行。 + +#### 存储过程 + +迄今为止,我们使用的大多数SQL语句都是针对一个或多个表的单条语句,但在实际开发中经常会遇到某个操作需要多条SQL语句才能完成的情况。例如,电商网站在受理用户订单时,需要做以下一系列的处理。 + +1. 通过查询来核对库存中是否有对应的物品以及库存是否充足。 +2. 如果库存有物品,需要锁定库存以确保这些物品不再卖给别人, 并且要减少可用的物品数量以反映正确的库存量。 +3. 如果库存不足,可能需要进一步与供应商进行交互或者至少产生一条系统提示消息。 +4. 不管受理订单是否成功,都需要产生流水记录,而且需要通知对应的用户。 + +我们可以通过创建存储过程来解决这些问题。简单的说,存储过程就是为以后的使用而保存的一条或多条MySQL语句的集合。通过存储过程,可以将复杂的操作封装起来,而且有助于保证数据的一致性;如果将来业务发生了变动,只需要调整修改存储过程即可。对于调用存储过程的用户来说,存储过程并没有暴露数据表的细节,而且执行存储过程比执行单独的SQL要快。 + +下面的存储过程实现了查询某门课程的最高分、最低分和平均分。 + +```SQL +delimiter $$ + +create procedure sp_get_score(courseId int, + out maxScore decimal(4,1), + out minScore decimal(4,1), + out avgScore decimal(4,1)) +begin + select max(score) into maxScore from tb_record where cid=courseId; + select min(score) into minScore from tb_record where cid=courseId; + select avg(score) into avgScore from tb_record where cid=courseId; +end $$ + +delimiter ; +``` + +> 说明:在定义存储过程时,因为可能需要书写多条SQL,而分隔这些SQL需要使用分号作为分隔符,如果这个时候,仍然用分号表示整段代码结束,需要执行这段代码,那么定义存储过程的SQL就会出现错误,所以上面我们用`delimiter $$`将整段代码结束的标记定义为`$$`,那么代码中的分号将不再表示整段代码的结束,直到遇到`end $$`整段代码才输入完成。定义完存储过程后,我们又将通过`delimiter ;`将结束符改回成分号。 + +上面定义的存储过程有四个参数,其中第一个参数是输入参数,代表课程的编号,后面的参数都是输出参数,因为存储过程不能定义返回值,只能通过输出参数将执行结果带出,定义输出参数的关键字是`out`,默认情况下参数都是输入参数。 + +调用存储过程。 + +```SQL +call sp_get_score(1111, @a, @b, @c); +``` + +获取输出参数的值。 + +```SQL +select @a as 最高分, @b as 最低分, @c as 平均分; +``` + +删除存储过程。 + +```SQL +drop procedure sp_get_score; +``` ### 相关知识 @@ -482,7 +586,7 @@ - 提交事务 - ```Shell + ```SQL commit ```