• [MySQL]视图、存储过程、触发器



    1. 视图

    视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。
    通俗的讲,视图只保存了查询的SQL逻辑,不保存查询结果。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上

    作用:

    • 简单
      视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视图,从而使得用户不必为以后的操作每次指定全部的条件。
    • 安全
      数据库可以授权,但不能授权到数据库特定行和特定的列上。通过视图用户只能查询和修改他们所能见到的数据
    • 数据独立
      视图可帮助用户屏蔽真实表结构变化带来的影响

    1.1 视图的基本操作

    #创建
    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] 视图名称 [,视图名称]..
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    eg

    #创建视图
    create or replace view stu_v_1 as select id,name from student where id <= 10;
    
    #查询视图
    show create view stu_v_1;
    select * from stu_v_1;
    select * from stu_v_1 where id<3;
     
    #修改视图
    create or replace view stu_v_1 as select id,name,num from student where id <= 10;
    alter view stu_v_1 as select id,name,num from student where id <=10;
    
    #删除视图
    drop view if exists stu_v_1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1.2 视图的检查选项

    当使用with check option子句创建视图时,MySOL会通过视图检查正在更改的每个行,例如插入,更新,删除,以使其符合视图的定义。
    MySQL允许基于另一个视图创建视图,它还会检查依赖视图中的规则以保持一致性。为了确定检查的范围,mysql提供了两个选项:
    cascadedlocal默认值为CASCADED

    create view v1 as select id,name from student where id <= 20 with cascaded check option;
    create view v1 as select id,name from student where id <= 20 with local check option;
    
    • 1
    • 2

    cascaded 的有向上传递性,即a2基于a1创建,a1没有check option ,a2 有, 那么a1也会变得拥有这个属性
    local 并没有
    检查的时候都会递归检查是否有check option并服从条件


    1.3 视图的更新

    要使视图可更新,视图中的行与基础表中的行之间必须存在一对一的关系。如果视图包含以下任何一项,则该视图不可更新:

    1. 聚合函数或窗口函数 : SUM() 、MIN() 、MAX()、 COUNT() 等
    2. distinct
    3. group by
    4. having
    5. union或者union all

    eg

    #创建视图,使用聚合函数
    create view stu_v_count as select count(*) from student;
    insert into stu_v_count vaLues(10); #报错
    
    • 1
    • 2
    • 3
    #1.为了保证数据库表的安全性,开发人员在操作tb_user表时,只能看到的用户的基本字段,屏蔽手机号邮箱两个字段
    create view tb_user_view as select id,name,profession,age,gender,status,createtime from tb_user;
    select from tb_user_view;
    
    #2.查询每个学生所选修的课程(三张表联查),这个功能在很多的业务中都有使用到,为了简化操作,定义一个视图。
    create view tb-stu_course_view as select S.name stu_name,S.no,c.name cou_name from student S,student_course sc,course c where S.id = Sc.studentid and sc.courseid = c.id;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2. 存储过程

    存储过程是事先经过编译并存储在数据库中的一段SQL语句的集合,调用存储过程可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的.
    存储过程思想上很简单 就是数据库SQL语言层面的代码封装与重用。

    特点:

    • 封装,复用
    • 可以接受参数,也可以返回数据
    • 减少网络交互,效率提升

    2.1 存储过程的基本语法

    #创建
    create procedure 存储过程的名称([参数列表])
    begin
    	--SQL语句
    end;
    
    #调用
    call 存储过程名称([参数]);
    
    #查看
    select * from information_scheme.routines where routine_scheme = 'xxx'; #查询指定数据库的存储过程及状态信息
    show create procedure 存储过程名称; #查询某个存储过程的定义
    #eg
    select * from information_schema.routines where routine_schema = '9tse';
    
    #删除
    drop procedure [if exists] 存储过程的名称;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    如果在命令行中执行创建存储过程的SQL时,需要关键字delimiter 指定SQL语句的结束符

    delimiter $$
    create procedure test()
    begin
    	select count(*) from student;
    end$$;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.2 变量

    2.2.1 系统变量

    系统变量是MySQL服务器提供的,不是用户定义的,属于服务器层面,分为全局变量(global),会话变量(session)

    #查看系统变量
    show [session | global] variables; 				--查看所有系统变量
    show [session | global] variables like '....';	--可以通过like模糊匹配方式查找变量
    select @@[session | global] 系统变量名;			--查看指定变量的值
    #设置系统变量
    set [session | global] 系统变量名 =;
    set @@[session | global]系统变量名 =;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ps

    • 如果没有指定session/global,默认是session,会话变量
    • MySQL服务器重新启动之后,所设置的全局参数会失效,要想不失校,可以在 /etc/my.cnf 中配置

    2.2.2 用户定义的变量

    用户定义变量是用户根据需要自己定义的变量,用户变量不用提前声明,在用的时候直接用@变量名 使用就可以。其作用域为当前连接

    #赋值
    set @var_name = expr;
    set @var_name := expr;
    select @var_name := expr;
    select 字段名 into @var_name from 表名;
    
    #使用
    select @var_name;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ps

    • 用户定义的变量无需对其进行声明或初始化,只不过获取到的值为NULL
    • 推荐使用 := 避免和=(判相等)认混
    set @mygender :='男';
    select @mycolor := 'red';
    select count(*) into @mycount from tb_user;
    
    • 1
    • 2
    • 3

    2.2.3 局部变量

    局部变量是根据需要定义的在局部生效的变量,访问之前,需要DECLARE声明。可用作存储过程内的局部变量和输入参数,局部变量的范围是在其内声明的begin,end块

    #声明
    declare 变量名 变量类型 [default ...];
    变量类型就是数据库字段类型:INTBIGINTCHARVARCHARDATETIME等。
    
    #赋值
    SET 变量名=值;
    SET 变量名:=SELECT 字段名 INTO 变量名 FROM 表名...;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.3 关键字

    存储过程的参数

    类型含义
    in(默认)该类参数作为输入,也就是需要调用时传入值
    out该类参数作为输出,也就是该参数可以作为返回值
    inout既可以作为输入参数,也可以作为输出参数
    create procedure 存储过程名称([ in/out/inout 参数名 参数类型])
    begin
    	...
    end;
    
    • 1
    • 2
    • 3
    • 4

    2.3.1 判断

    if

    #语法
    if 条件1 then
    	...
    elseif 条件2 then --可选
    	...
    else			--可选
    	... 
    end if;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    case

    case case_value
            when search_condition1 then statement_List1
            [when search_condition2 then statement_list2] ..
            [else statement_list]
    end case;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    eg

    create procedure p6(in month int)
    begin
          declare result varchar(10);
          case
                when month >= 1 and month <= 3 then
                   set result := '第1季度';
                when month >= 4 and month <= 6 then
                   set result := '第2季度';
                when month >= 7 and month1<=9 then
                   set result := '第3季度';
                when month >= 10 and month <= 12 then
                   set result := '第4季度';
                else
                   set result := '非法参数';
          end case
          select concat('您输入的月份为:',month,'所属的季度为:',resut);
    end;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.3.2 循环

    while
    while循环是有条件的循环控制语句。满足条件后,再执行循环体中的SQL语句。
    具体语法为:

    #先判定条件,如果条件为true,则执行逻辑,否则,不执行逻辑
    while 条件 do
         SQL逻辑.
    end while;
    
    • 1
    • 2
    • 3
    • 4

    eg

    create procedure p(in n int)
    begin 
    	declare total int default 0;
    	while n>0 do
    		set total := total +n;
    		set n := n-1;
    	end while;
    	select total;
    end;
    
    call p(100);	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    repeat
    repeat是有条件的循环控制语句,当满足条件的时候退出循环。具体语法为:

    #先执行一次逻辑,然后判定逻辑是否满足,如果满足,则退出。如果不满足,则继续下一次循环
    repeat
          SQL..
          until 条件
    end repeat;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    eg

    create procedure p(in n int)
    begin
    	declare total int default 0;
    	repeat
    		set total := total+n;
    		set n:= n-1;
    	until n<=0
    	end repeat;
    	select total;
    end;
    
    call p(10);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    loop
    LOOP实现简单的循环,如果不在SQL逻辑中增加退出循环的条件,可以用其来实现简单的死循环。
    LOOP可以配合以下两个语句使用:
    LEAVE:配合循环使用,退出循环。
    TERATE:必须用在循环中,作用是跳过当前循环剩下的语句,直接进入下一次循环

    [begin_label:] loop
          SQL逻辑...
    end loop [end_label];
    
    leave label   --退出指定标记的循环体
    iterate label --直接进入下一次循环
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    eg

    #1
    create procedure p(in n int)
    begin
    	declare total int default 0;
    	sum: loop
    		if n<=0 then
    			leave sum;
    		end if;
    		set total := total+n;
    		set n:=n-1;
    	end loop sum;
    	select  total;
    end;
    
    call p(90);
    
    
    #2
    create procedure p2(in n int)
    begin
    	declare total int default 0;
    	sum:loop
    		if n<=0 then
    			leave sum;
    		end if;
    		if n%2 == 1 then
    			set n := n-1;
    			iterate sum;
    		end if;
    		set total := total + n;
    		set n := n-1;
    	end loop sum;
    	select total;
    end;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    2.4 游标

    游标(CURSOR)是用来存储查询结果集的数据类型,在存储过程和函数中可以使用游标对结果集进行循环的处理。
    游标的使用包括游标的声明、OPEN、FETCH和CLOSE,其语法分别如下。

    #声明游标
    declare 游标名称 cursor for 查询语句;
     
    #打开游标
    open 游标名称;
     
    #获取游标记录
    fetch 游标名称 into 变量[,变量];
     
    #关闭游标
    close 游标名称;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    条件处理程序
    可以用来定义在流程控制结构执行过程中遇到问题时相应的处理步骤

    declare hander_action handler for condition_value [,condition_value] ... statement;
    
    handler_action
    	continue:继续执行当前程序
    	exit : 种植执行当前程序
    condition_value
    	sqlstate sqlstate_value : 状态码,02000
    	sqlwarning : 所有以01开头的sqlstate代码的简写
    	not found : 所有以02开头的sqlstate代码的简写
    	sqlexception : 所有没有被sqlwarning 或 notfound 捕获的sqlstate代码的简写
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    eg

    create procedure p(in uage int)
    begin
    	declare uname varchar(100);
    	declare upro varchar(100);
    	declare u_cursor cursor for select name,profession from tb_user where age <= uage;
    	declare exit handler for sqlstate '02000' close u_cursor;
    	#declare exit handler for not found close u_cursor;
    	
    	drop table if exists tb_user_pro;
    	create table if not exists tb_user_pro(
    		id int primary key auto_increment,
    		name varchar(100),
    		profession varchar(100)
    	);
    	
    	open u_cursor;
    	while true do
    		fetch u_cursor into uname,upro;
    		insert into tb_user_pro values(null,uname,upro);
    	end while;
    	close u_cursor;
    end;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.5 存储函数

    存储函数在实际中应用不广泛,可以被存储过程代替
    其参数只能时in类型

    create function 存储函数名称([参数列表])
    return type [characteristic...]
    begin
    	SQL
    	return ...;
    end;
    
    characteristic说明:
    deterministic :相同的输入参数总是产生相同的结果
    no sql : 不包含SQL语句
    reads sql data : 包含读取数据的语句,但不包含写入数据的语句
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    eg

    create function fun(n int)
    return int deterministic
    begin
    	declare total int default 0;
    	while n>0 do
    		set total := total + n;
    		set n := n-1;
    	end while;
    	return total;
    end;
    
    select fun(50);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3. 触发器

    触发器是与表有关的数据库对象,指在insert/update/delete之前或之后,触发并执行触发器中定义的SQL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性,日志记录,数据校验等操作。
    使用别名oldnew来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。
    现在触发器还只支持行级触发,不支持语句级触发。

    触发器类型new和old
    insert 型触发器new表示将要或已经新增的数据
    update 型触发器old表示修改之前的数据,new表示将要或已经修改后的数据
    delete 型触发器. old表示将要或者已经删除的数据
    #创建
    create tigger trigger_name
    before/after insert/update/delete
    on tb_name for each row --行级触发器
    begin
    	trigger_stmt;
    end;
    
    #查看
    show triggers;
    
    #删除
    drop trigger [schema_name.]trigger_name; --如果没有指定schema_name 默认为当前数据库
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    eg

    #需求:通过发器记录user表的数据变更日志(user_ogs),包含培加,修改,除;
    #准备工作:口志表userlogs
    create table user_logs(
        id int(11not null auto_increment,
        operation varchar(20) not null comment'操作类型,insert/update/delete',
        operate_time datetime not nul comment'操作时间',
        operate_id int(11not null comment'操作的ID',
        operate_params varchar(500comment'操作参数',
        primary key('id')
    )engine=innodb default charset=utf8;
    
    create trigger tb_user_insert_trigger
    	after insert on tb_user for each row
    begin
    	insert into user_logs(id,operation,operate_time,operate_id,operate_params)values
    	(null,'insert',now(),new.id,concat('insert msg : ' ,new.id,.....)
    end;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

  • 相关阅读:
    关于c++中成员函数做友元的详细解释
    U_BOOT_DRIVER简析
    uniapp适配问题
    MATLAB | MATLAB海洋、气象数据colormap配色补充包(NCL color tables)
    Android Compose Dialog唤起键盘后,键盘遮挡Dialog底部内容或者底部TextField顶起不完美的解决方法
    轻量封装WebGPU渲染系统示例<37>- 多个局部点光源应用于非金属材质形成的效果(源码)
    IMAU鸿蒙北向开发-2023年9月5日学习日志
    springboot整合redis
    6.1 KMP算法搜索机器码
    【C++】类和对象——拷贝构造函数
  • 原文地址:https://blog.csdn.net/sewerperson/article/details/133832894