【Mysql】Mysql视图、触发器、存储过程、游标

一、视图

定义

视图(view)是一种虚拟存在的表,是一个逻辑表,本身并不包含数据。其内容由查询定义。

基表:用来创建视图的表叫做基表;

通过视图,可以展现基表的部分数据;

视图数据来自定义视图的查询中使用的表,使用视图动态生成;

优点

简单:使用视图的用户完全不需要关心后面对应的表的结构、关联条件和筛选条件,对用户来说已
经是过滤好的复合条件的结果集。

安全:使用视图的用户只能访问他们被允许查询的结果集,对表的权限管理并不能限制到某个行某
个列,但是通过视图就可以简单的实现。

数据独立:一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影
响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响。

语法
CREATE VIEW <视图名> AS <SELECT语句>
准备
CREATE TABLE `user` ( 
	`id` INT auto_increment COMMENT '编号', 
	`name` VARCHAR (32) COMMENT '学生姓名', 
	`sex` TINYINT DEFAULT 1 COMMENT '性别(1:男;0:女)', 
	`age` TINYINT DEFAULT 18 COMMENT '年龄', 
	PRIMARY KEY (`id`) 
) COMMENT = '学生表' ENGINE = INNODB; 

CREATE TABLE `goods` ( 
	`id` INT auto_increment COMMENT '编号', 
	`name` VARCHAR (32) COMMENT '商品名称', 
	`price` DECIMAL (10, 6) DEFAULT 0 COMMENT '价格', 
	PRIMARY KEY (`id`)
 ) COMMENT = '商品表' ENGINE = INNODB; 

CREATE TABLE `user_goods` ( 
	`id` INT auto_increment COMMENT '编号', 
	`user_id` INT COMMENT '用户ID', 
	`goods_id` INT COMMENT '商品ID', 
	PRIMARY KEY (`id`)
 ) COMMENT = '用户商品表' ENGINE = INNODB; 

-- 创建视图 
CREATE VIEW view_test1 AS SELECT
	 `user`.id AS user_id, 
	 `user`.`name` AS user_name,
	 `user`.`sex` AS user_sex,
	 `user`.`age` AS user_age, 
	 `goods`.id AS goods_id, 
	 `goods`.`name` AS goods_name 
 FROM
 	`user`
 JOIN `user_goods` ON `user`.id = `user_goods`.user_id 
 JOIN `goods` ON `goods`.id = `user_goods`.goods_id;
 
-- 调用 
SELECT * FROM view_test1; 
-- 删除视图 
DROP VIEW view_test1;
作用
  • 可复用,减少重复语句书写;类似程序中函数的作用;
  • 重构利器
    假如因为某种需求,需要将user拆房表usera和表userb;如果应用程序使用sql语句:
    select * from user 那就会提示该表不存在;若此时创建视图 create view user as select a.name,a.age,b.sex from usera as a, userb as b where a.name=b.name; ,则只需要更改数据库结构,而不需要更改应用程序;
    视图在oracle 物化视图 mysql select * from
  • 逻辑更清晰,屏蔽查询细节,关注数据返回;
  • 权限控制,某些表对用户屏蔽,但是可以给该用户通过视图来对该表操作;

二、触发器

触发器是否具备事务性?否。

定义

触发器(trigger)是MySQL提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表
事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比
如当对一个表进行DML操作( insert , delete , update )时就会激活它执行。

4要素
  • 监视对象: table
  • 监视事件: insert 、 update 、 delete
  • 触发时间: before , after
  • 触发事件: insert 、 update 、 delete
语法
CREATE TRIGGER trigger_name 
trigger_time trigger_event 
ON tbl_name FOR EACH ROW 
	[trigger_order] 
trigger_body -- 此处写执行语句 

-- trigger_body: 可以一个语句,也可以是多个语句;多个语句写在 BEGIN ... END 间 
-- trigger_time: { BEFORE | AFTER } 
-- trigger_event: { INSERT | UPDATE | DELETE } 
-- trigger_order: { FOLLOWS | PRECEDES } other_trigger_name 12345678910
准备
CREATE TABLE `work` ( 
	`id` INT PRIMARY KEY auto_increment, 
	`address` VARCHAR (32)
 ) DEFAULT charset = utf8 ENGINE = INNODB; 

CREATE TABLE `time` ( 
	`id` INT PRIMARY KEY auto_increment, 
	`time` DATETIME 
) DEFAULT charset = utf8 ENGINE = INNODB; 

CREATE TRIGGER trig_test1 AFTER INSERT 
ON `work` FOR EACH ROW 
INSERT INTO `time` VALUES(NULL,NOW()); 123456789
NEW 和 OLD

在 INSERT 型触发器中, NEW 用来表示将要( BEFORE )或已经( AFTER )插入的新数据;

在 DELETE 型触发器中, OLD 用来表示将要或已经被删除的原数据;

在 UPDATE 型触发器中, OLD 用来表示将要或已经被修改的原数据, NEW 用来表示将要或已经修
改为的新数据;

NEW.columnName (columnName为相应数据表某一列名) 
OLD.columnName (columnName为相应数据表某一列名)
案例

在下订单的时候,对应的商品的库存量要相应的减少,即买几个商品就减少多少个库存量。

准备

CREATE TABLE `goods` ( 
	`id` INT PRIMARY KEY auto_increment, 
	`name` VARCHAR (32), 
	`num` SMALLINT DEFAULT 0 
);

CREATE TABLE `order` ( 
	`id` INT PRIMARY KEY auto_increment, 
	`goods_id` INT, 
	`quantity` SMALLINT COMMENT '下单数量' 
);

INSERT INTO goods VALUES (NULL, 'C++', 40); 
INSERT INTO goods VALUES (NULL, 'C', 63); 
INSERT INTO goodS VALUES (NULL, 'mysql', 87); 
INSERT INTO `order` VALUES (NULL, 1, 3); 
INSERT INTO `order` VALUES (NULL, 2, 4);

需求1

客户修改订单购买的数量,在原来购买数量的基础上减少2个;

-- delimiter 
-- delimiter是mysql分隔符,在mysql客户端中分隔符默认是分号 ;。如果一次输入的语句较多, 并且语句中间有分号,这时需要重新指定一个特殊的分隔符。通常指定 $$ 或 || 
delimiter // 
CREATE TRIGGER trig_order_1 AFTER INSERT 
ON `order` FOR EACH ROW 
BEGIN
	UPDATE goods SET num = num - 2 WHERE id = 1; 
END
// 
delimiter ; 
INSERT

需求2

客户修改订单购买的数量,商品表的库存数量自动改变;

delimiter // 
CREATE TRIGGER trig_order_2 BEFORE UPDATE 
ON `order` FOR EACH ROW 
BEGIN
	UPDATE goods SET num=num+old.quantity-new.quantity WHERE id = new.goods_id; 
END 
//
delimiter ; 

-- 测试 
UPDATE `order` SET quantity = quantity+2 WHERE id = 1;

三、存储过程

定义

SQL语句需要先编译然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL
语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带
有参数)来调用执行它。

存储过程是可编程的函数,在数据库中创建并保存,可以由SQL语句和控制结构组成。当想要在不
同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中
的存储过程可以看做是对编程中面向对象方法的模拟,它允许控制数据的访问方式。

特点
  • 能完成较复杂的判断和运算 有限的编程
  • 可编程行强,灵活
  • SQL编程的代码可重复使用
  • 执行的速度相对快一些
  • 减少网络之间的数据传输,节省开销
语法
CREATE PROCEDURE 过程名([[IN|OUT|INOUT] 参数名 数据类型[,[IN|OUT|INOUT] 参数名 数 据类型…]]) [特性 ...] 过程体

存储过程根据需要可能会有输入、输出、输入输出参数,如果有多个参数用","分割开。

MySQL 存储过程的参数用在存储过程的定义,共有三种参数类型 IN , OUT , INOUT 。

IN:参数的值必须在调用存储过程时指定,0在存储过程中修改该参数的值不能被返回,可以设
置默认值

OUT:该值可在存储过程内部被改变,并可返回

INOUT:调用时指定,并且可被改变和返回过程体的开始与结束使用 BEGIN 与 END 进行标识。

案例
DELIMITER // 
	CREATE PROCEDURE proc_test1()
BEGIN 
	SELECT current_time(); 
	SELECT current_date(); 
END 
//
DELIMITER ; 
call proc_test1();

IN

DELIMITER // 
CREATE PROCEDURE proc_in_param (IN p_in INT) 
BEGIN
	SELECT
		p_in ; 
	SET 
		p_in = 2 ; 
	SELECT 
		p_in ; 
	END ;// 
DELIMITER ; 

-- 调用 
SET @p_in = 1; 

CALL proc_in_param (@p_in); 

-- p_in虽然在存储过程中被修改,但并不影响@p_id的值 
SELECT @p_in;=1

OUT

DELIMITER // 
	CREATE PROCEDURE proc_out_param(OUT p_out int) 
		BEGIN 
			SELECT p_out; 
			SET p_out=2; 
			SELECT p_out; 
		END; 
//
DELIMITER ; 

-- 调用 
SET @p_out=1; 
CALL proc_out_param(@p_out); 
SELECT @p_out; -- 2

INOUT

DELIMITER // 
	CREATE PROCEDURE proc_inout_param(INOUT p_inout int) 
		BEGIN 
			SELECT p_inout; 
			SET p_inout=2; 
			SELECT p_inout; 
		END; 
//
DELIMITER ; 

#调用 
SET @p_inout=1; 
CALL proc_inout_param(@p_inout) ; 
SELECT @p_inout; -- 2

四、游标

游标是针对行操作的,对从数据库中 select 查询得到的结果集的每一行可以进行分开的独立的相
同或者不相同的操作。

对于取出多行数据集,需要针对每行操作;可以使用游标;游标常用于存储过程、函数、触发器、
事件;

游标相当于迭代器

定义游标
DECLARE cursor_name CURSOR FOR select_statement;
打开游标
OPEN cursor_name;
取游标数据
FETCH cursor_name INTO var_name[,var_name,......]
关闭游标
CLOSE curso_name;
释放
DEALLOCATE cursor_name;
设置游标结束标志
DECLARE done INT DEFAULT 0; 
DECLARE CONTINUE HANDLER FOR NOT FOUND 
SET done = 1; -- done 为标记为
案例
CREATE PROCEDURE proc_while ( 
	IN age_in INT, 
	OUT total_out INT 
)
BEGIN 
-- 创建 用于接收游标值的变量 
DECLARE p_id,p_age,p_total INT ; 
DECLARE p_sex TINYINT ; 
-- 注意:接收游标值为中文时,需要给变量 指定字符集utf8 
DECLARE p_name VARCHAR (32) CHARACTER SET utf8 ; -- 游标结束的标志 
DECLARE done INT DEFAULT 0 ; -- 声明游标 
DECLARE cur_teacher CURSOR FOR SELECT 
	teacher_id, 
	teacher_name, 
	teacher_sex, 
	teacher_age 
FROM
	teacher 
WHERE
	teacher_age > age_in ; -- 指定游标循环结束时的返回值 
DECLARE CONTINUE HANDLER FOR NOT found 
SET done = 1 ; 
-- 打开游标 
OPEN cur_teacher ; 
-- 初始化 变量 
SET p_total = 0 ; 
-- while 循环 
WHILE done != 1 DO 
	FETCH cur_teacher INTO p_id, 
	p_name, 
	p_sex, 
	p_age ; 
IF done != 1 THEN 
SET p_total = p_total + 1 ; 
END IF ; 
END WHILE ; 
-- 关闭游标 
CLOSE cur_teacher ; 
-- 将累计的结果复制给输出参数 
SET total_out = p_total ; 
END
// 
delimiter ; 

-- 调用 
SET @p_age =20; 
CALL proc_while(@p_age, @total); 
SELECT @total;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值