一、视图
视图:是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。
视图的特点:
1.视图的列可以来自不同的表,是表的抽象和逻辑意义上建立的新关系;
2.视图是由基本表(实表)产生的表(虚表);
3.视图的建立和删除不影响基本表;
4.对视图内容的更新(添加、删除和修改)直接影响基本表;
5.当视图来自多个基本表时,不允许添加和删除数据。
-- 创建视图 create view 视图名 as sql语句; create view v1 as select id,name from userinfo; -- 使用视图 select * from 视图名; select * from v1; -- 更新视图 alter view 视图名 as sql语句; alter view v1 as select id,name from userinfo where id<10; -- 删除视图 drop view 视图名; drop view v1;
二、触发器
触发器:监视某种情况,并触发某种操作;对某个表进行【增/删/改】操作的前后如果希望触发某个特定的行为时,可以使用触发器,触发器用于定制用户对表的行进行【增/删/改】前后的行为。
触发器创建语法四要素:
1.监视地点(table)
2.监视事件(insert/update/delete)
3.触发时间(after/before)
4.触发事件(insert/update/delete)
-- 创建触发器语法 create trigger 触发器名 after/before insert/update/delete on 表名 for each row -- 这句是固定的 begin -- begin和end中间放置需要执行的sql语句 end after/before:只能选一个 , after(后置触发), before(前置触发) insert/update/delete:只能选一个
下面来介绍如何使用触发器
-- 商品表 create table goods_tb( id int primary key auto_increment, name varchar(20), num int ); -- 订单表 create table order_tb( oid int primary key auto_increment, gid int, gnum int ); -- 添加3条商品数据 insert into goods_tb(name,num) values('商品1',10),('商品2',10),('商品3',10);
如果我们在没使用触发器之前,假设我们现在卖了3个商品1,则我们需要做两件事:
-- 1.往订单表插入一条记录 insert into order_tb(gid,gnum) values(1,3); -- 2.更新商品表商品1的剩余数量 update goods_tb set num=num-3 where id=1;
现在,我们来创建一个触发器:
create trigger tg1 after insert on order_tb for each row begin update goods_tb set num=num-3 where id=1; end
这时候我们只要执行:
insert into order_tb(gid,gnum) values(1,3);
会发现商品1的数量变为7了,说明在我们插入一条订单的时候,触发器自动帮我们做了更新操作。
但现在会有一个问题,因为我们触发器里面num和id都是写死的,所以不管我们买哪个商品,最终更新的都是商品1的数量。比如:我们往订单表再插入一条记录:
insert into order_tb(gid,gnum) values(2,3);
执行完后会发现商品1的数量变4了,而商品2的数量没变,这显然不是我们想要的结果。我们需要改进之前创建的触发器。
我们需要知道在触发器中引用行的值,也就是说要得到新插入的订单记录中的gid或gnum的值。
对于insert而言,即将插入的数据行用new来表示,行中的每一列的值用 new.字段名 来表示。
所以可以这样来修改触发器:
create trigger tg2 after insert on order_tb for each row begin update goods_tb set num=num-new.gnum where id=new.gid; end
第二个触发器创建完毕后,把第一个触发器删掉:
drop trigger tg1;
再来测试一下,插入一条订单记录:
insert into order_tb(gid,gnum) values(2,3);
执行完发现商品2的数量变为7了,现在就对了。
但是,现在还存在两个其他的问题:
# 1.当用户撤销一个订单的时候,我们这边直接删除一个订单,我们是不是需要把对应的商品数量再加回去呢? 对于delete而言,即将删除的数据行用old来表示,原表本来有一行,但客户取消了交易(相当于删除了这一行数据),如果想引用被删除的这一行,用 old.字段名 可以引用删除的值。 那我们的触发器就该这样写:
客户取消订单,则触发器该这样设计:
create trigger tg3 after delete on order_tb for each row begin update goods_tb set num=num+old.gnum where id=old.gid; end
假如客户取消了交易,那么就会执行下面这条sql语句:
delete from order_tb where id=1;
这时,我们再看看商品归还没有;
一看,客户的订单成功取消了,商品也归还了,非常好。
# 2.当客户修改一个订单的数量时,我们触发器修改怎么写?
还是上面这个数据:假如客户觉得数量少了,需要改为订购5个商品1,则触发器该这样设计:
create trigger tg4 after update on order_tb for each row begin update goods_tb set num=num+old.gnum-new.gnum where id=old.gid; -- new表示即将插入的数据行,old表示即将删除的数据行。(这里num=7+3-5) end
执行以下sql语句:
update order_tb set gnum=5 where id=1;
成功完成操作啦
三、存储过程
存储过程:存储过程是为了完成某个数据库中的特定功能而编写的语句集合;该语句集包括SQL语句(对数据的增删改查)、条件语句和循环语句等......当主动去调用存储过程时,其中内部的SQL语句会按照逻辑执行。
-- 看现有的存储过程 show procedure status; -- 创建存储过程(无参数示例) create procedure p1() begin select * from t1; end -- 调用存储过程 call 存储过程名称(参数类型 参数名 数据类型); -- 删除存储过程 drop procedure 存储过程名称;
有参数存储过程:
create procedure p2(in i int,inout io varchar(50)) begin update goods_tb set name=io where id=i; end set @io="商品100"; # 设置初始值 call p2(3,@io); # 执行存储调用 select @io; # 拿到结果![]()
create procedure p3(in i int,out o varchar(50)) begin select name into o from teacher where id = i; end set @name=null; call p3(1,@name); select @name;
对于存储过程,可以接收参数,其参数有三类:
in 仅用于传入参数用
out 仅用于返回值用
inout 既可以传入又可以当作返回值
PS: into关键字可以将前面字段的查询结果执行给 into 后面的变量
create procedure p_in(in num int) begin select num; set num=100; select num; end; set @num=1; call p_in(@num); select @num; # 总结: in 参数只是将变量在存储过程内部做了修改,并没有影响到外部,@num仍为1。