• 数据库存储过程和触发器


    存储过程和触发器

    存储过程简介

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

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

    (1).增强SQL语言的功能和灵活性:存储过程可以用控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。

    (2).标准组件式编程:存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的SQL语句。而且数据库专业人员可以随时对存储过程进行修改,对应用程序源代码毫无影响。

    (3).较快的执行速度:如果某一操作包含大量的Transaction-SQL代码或分别被多次执行,那么存储过程要比批处理的执行速度快很多。因为存储过程是预编译的。在首次运行一个存储过程时查询,优化器对其进行分析优化,并且给出最终被存储在系统表中的执行计划。而批处理的Transaction-SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。

    (4).减少网络流量:针对同一个数据库对象的操作(如查询、修改),如果这一操作所涉及的Transaction-SQL语句被组织进存储过程,那么当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而大大减少网络流量并降低了网络负载。

    (5).作为一种安全机制来充分利用:通过对执行某一存储过程的权限进行限制,能够实现对相应的数据的访问权限的限制,避免了非授权用户对数据的访问,保证了数据的安全。

    MySQL的存储过程

    存储过程是数据库的一个重要的功能,MySQL 5.0以前并不支持存储过程,这使得MySQL在应用上大打折扣。好在MySQL 5.0开始支持存储过程,这样即可以大也可以提高数据库编程的灵活性。

    MySQL存储过程的创建

    语法

    CREATE PROCEDURE  过程名([[IN|OUT|INOUT] 参数名 数据类型[,[IN|OUT|INOUT] 参数名 数据类型…]]) [特性 ...] 过程体
    分隔符
    
    • 1
    • 2

    MySQL默认以";“为分隔符,如果没有声明分割符,则编译器会把存储过程当成SQL语句进行处理,因此编译过程会报错,所以要事先用“DELIMITER //”声明当前段分隔符,让编译器把两个”//"之间的内容当做存储过程的代码,不会执行这些代码;“DELIMITER ;”的意为把分隔符还原。

    参数

    存储过程根据需要可能会有输入、输出、输入输出参数,如果有多个参数用","分割开。MySQL存储过程的参数用在存储过程的定义,共有三种参数类型,IN,OUT,INOUT:

    • IN参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值**(只能被查询,不能被修改(修改无效))**
    • OUT:该值可在存储过程内部被改变,并可返回(只能被修改,不能被查询(查询为空值))
    • INOUT:调用时指定,并且可被改变和返回(既可以被查询也可以被修改)

    过程体

    · 过程体的开始与结束使用BEGINEND进行标识。

    变量

    语法:

    DECLARE 变量名1[,变量名2...] 数据类型 [默认值];
    
    • 1

    注意:数据类型为varchar等需要给长度(255),int不用

    变量赋值

    语法:

    SET 变量名 = 变量值 [,变量名= 变量值 ...]
    
    • 1

    用户变量

    用户变量一般以@开头

    注意:滥用用户变量会导致程序难以理解及管理

    注释

    MySQL存储过程可使用两种风格的注释:

    · 双杠:–,该风格一般用于单行注释

    MySQL存储过程的调用

    用call和你过程名以及一个括号,括号里面根据需要,加入参数,参数包括输入参数、输出参数、输入输出参数。

    call 过程名([参数]);
    
    • 1

    MySQL存储过程的删除

    DROP PROCEDURE if EXISTS 过程名;
    
    • 1

    MySQL存储过程的控制语句

    变量作用域

    内部变量在其作用域范围内享有更高的优先权,当执行到end时,内部变量消失,不再可见了,在存储
    过程外再也找不到这个内部变量,但是可以通过out参数或者将其值指派给会话变量来保存其值。

    条件语句

    1. IF-THEN-ELSE语句
    IF var=0 THEN
          ......
    END IF ;
        IF var=0 THEN
          ....
    ELSE
          .......
        END IF ;
     
    2. CASE-WHEN-THEN-ELSE语句
    CASE var
            WHEN 0 THEN
              ......
            WHEN 1 THEN
              .....
            ELSE
              .....
          END CASE ;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    循环语句

    WHILE-DOEND-WHILE
           WHILE var<6 DO
                  .....
           END WHILE ;
    
    • 1
    • 2
    • 3
    • 4

    MySQL存储过程的基本函数

    字符串类

    CHARSET(str) //返回字串字符集
    CONCAT (string2 [,… ]) //连接字串
    INSTR (string ,substring ) //返回substring首次在string中出现的位置,不存在返回0
    LCASE (string2 ) //转换成小写
    LEFT (string2 ,length ) //从string2中的左边起取length个字符
    LENGTH (string ) //string长度
    LOAD_FILE (file_name ) //从文件读取内容
    LOCATE (substring , string [,start_position ] ) 同INSTR,但可指定开始位置
    LPAD (string2 ,length ,pad ) //重复用pad加在string开头,直到字串长度为length
    LTRIM (string2 ) //去除前端空格
    REPEAT (string2 ,count ) //重复count次
    REPLACE (str ,search_str ,replace_str ) //在str中用replace_str替换search_str
    RPAD (string2 ,length ,pad) //在str后用pad补充,直到长度为length
    RTRIM (string2 ) //去除后端空格
    STRCMP (string1 ,string2 ) //逐字符比较两字串大小,
    SUBSTRING (str , position [,length ]) //从str的position开始,取length个字符,
    注:mysql中处理字符串时,默认第一个字符下标为1,即参数position必须大于等于1

    TRIM([[BOTH|LEADING|TRAILING] [padding] FROM]string2) //去除指定位置的指定字符
    UCASE (string2 ) //转换成大写
    RIGHT(string2,length) //取string2最后length个字符
    SPACE(count) //生成count个空格
    
    • 1
    • 2
    • 3
    • 4

    数学类

    ABS (number2 ) //绝对值
    BIN (decimal_number ) //十进制转二进制
    CEILING (number2 ) //向上取整
    CONV(number2,from_base,to_base) //进制转换
    FLOOR (number2 ) //向下取整
    FORMAT (number,decimal_places ) //保留小数位数
    HEX (DecimalNumber ) //转十六进制
    注:HEX()中可传入字符串,则返回其ASC-11码,如HEX(‘DEF’)返回4142143
    也可以传入十进制整数,返回其十六进制编码,如HEX(25)返回19
    LEAST (number , number2 [,…]) //求最小值
    MOD (numerator ,denominator ) //求余
    POWER (number ,power ) //求指数
    RAND([seed]) //随机数
    ROUND (number [,decimals ]) //四舍五入,decimals为小数位数] 注:返回类型并非均为整数

    SIGN (number2 ) // 正数返回1,负数返回-1

    日期时间类

    ADDTIME (date2 ,time_interval ) //将time_interval加到date2
    CONVERT_TZ (datetime2 ,fromTZ ,toTZ ) //转换时区
    CURRENT_DATE ( ) //当前日期
    CURRENT_TIME ( ) //当前时间
    CURRENT_TIMESTAMP ( ) //当前时间戳
    DATE (datetime ) //返回datetime的日期部分
    DATE_ADD (date2 , INTERVAL d_value d_type ) //在date2中加上日期或时间
    DATE_FORMAT (datetime ,FormatCodes ) //使用formatcodes格式显示datetime
    DATE_SUB (date2 , INTERVAL d_value d_type ) //在date2上减去一个时间
    DATEDIFF (date1 ,date2 ) //两个日期差
    DAY (date ) //返回日期的天
    DAYNAME (date ) //英文星期
    DAYOFWEEK (date ) //星期(1-7) ,1为星期天
    DAYOFYEAR (date ) //一年中的第几天
    EXTRACT (interval_name FROM date ) //从date中提取日期的指定部分
    MAKEDATE (year ,day ) //给出年及年中的第几天,生成日期串
    MAKETIME (hour ,minute ,second ) //生成时间串
    MONTHNAME (date ) //英文月份名
    NOW ( ) //当前时间
    SEC_TO_TIME (seconds ) //秒数转成时间
    STR_TO_DATE (string ,format ) //字串转成时间,以format格式显示
    TIMEDIFF (datetime1 ,datetime2 ) //两个时间差
    TIME_TO_SEC (time ) //时间转秒数]
    WEEK (date_time [,start_of_week ]) //第几周
    YEAR (datetime ) //年份
    DAYOFMONTH(datetime) //月的第几天
    HOUR(datetime) //小时
    LAST_DAY(date) //date的月的最后日期
    MICROSECOND(datetime) //微秒
    MONTH(datetime) //月
    MINUTE(datetime) //分返回符号,正负或0
    SQRT(number2) //开平方

    存储过程代码

    1. 判断存储过程是否存在 存在删除
    DROP PROCEDURE IF EXISTS 过程名;
    创建存储过程
    DELIMITER //
    CREATE 
     PROCEDURE  过程名(参数)
     BEGIN
    	过程体
     END//
    DELIMITER;
    
    2. 存储过程中创建变量--使用DECLARE关键字
    DELIMITER //
    CREATE 
     PROCEDURE  过程名(参数)
     BEGIN
    DECLARE 变量名 类型 [DEFAULT 0]默认值;  
    	过程体
     END//
    DELIMITER;
    
    3. 存储过程中带返回值--使用select返回
    DELIMITER //
    CREATE 
     PROCEDURE  过程名(参数)
     BEGIN
    DECLARE 变量名 类型 [DEFAULT 0]默认值;  
    	过程体
    
    Select 返回变量名    
    或
    Select  *  from 表名  (结果集)
    
     END//
    DELIMITER;
    
    4. 存储过程中使用循环
    DECLARE  var  int  DEFAULT 0 ; 
    	WHILE var<5 DO
    			INSERT INTO smbms_type(typename,typepid) values("1",1);
    			set i = i+1;
    	end WHILE;
    	
    5. 存储过程中使用事务
    DELIMITER //
    CREATE 
     PROCEDURE  过程名(参数)
     BEGIN
    DECLARE t_error INTEGER DEFAULT 0;  --定义变量
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1;  --异常时触发
      START TRANSACTION;  --开启事务
    
    		过程体
          IF t_error = 1 THEN  --判断
                ROLLBACK;  --回滚
            ELSE  
                COMMIT;  --提交
            END IF;  
    Select  t_error ; --返回状态
    
     END//
    DELIMITER;
     
    6. 存储过程中调用其它表数据
    select typename into @tn from smbms_type where typeid = 2;
    
    
    7. 调用存储过程
    Call 过程名(参数.....);
    
    • 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
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    存储过程示例
    -- 删除存储过程
    DROP PROCEDURE if EXISTS addStu;
    
    -- 创建存储过程
    CREATE PROCEDURE addStu(
    	-- 参数
    	stuname VARCHAR(255)
    )
    BEGIN
    	
    	SET stuname = '李文才';
    	
    	SELECT * from student where StudentName = stuname;
    end;
    
    -- 使用存储过程
    CALL addStu('张三');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    存储过程_事务示例
    -- 删除存储过程
    DROP PROCEDURE if EXISTS updmoney;
    
    -- 创建存储过程
    CREATE PROCEDURE updmoney()
    BEGIN
    	-- 定义变量
    	DECLARE t_error int DEFAULT 0;
    	-- 当事务发生异常时触发(当t_error=0提交事务,当t_error=1回滚事务)
    	DECLARE CONTINUE HANDLER for SQLEXCEPTION SET t_error = 1;
    	-- 开启事务
    	START TRANSACTION;
    	-- 过程体
    	update yhzz SET money = money + 100 WHERE id = 1;
    	UPDATE yhzz SET money = money - 100 + 'aaa' WHERE id = 2;
    	-- (用于调试方便查看异常状态)查看t_error的值
    	select t_error;
    	-- 对异常处理进行判断
    	IF t_error=0 THEN 
    		COMMIT;
    	ELSE
    		ROLLBACK;
    	END IF;
    end;
    
    -- 使用存储过程
    call updmoney();
    
    • 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

    触发器

    解释

    起到一个链接触发的作用,类似于蝴蝶效应,当执行一条带触发器的语句后会随之触发其相应的触发器,可顺带完成某种特定操作
    虽然可以减少一些操作,但会大大增加依赖性,反而出问题不方便

    具体使用方法

    1、在‘设计表’中选择触发器选项
    2、设置姓名,触发类型(before在执行执行体之前,after在执行执行体之后)
    3、选择用于插入更新删除中(删除中触发类型应选择before,因为选择after删除执行体都已经删完了,再触发时没有参数,没啥意义)
    4、在定义中输入语句,与存储过程的语法一样:

    begin
    ---执行体---
    end
    
    • 1
    • 2
    • 3

    注意点

    1、但与此不同的是触发器里面的参数分为oldnew
    old代表数据库原来的参数,new代表数据库新的参数
    一般old多用于删除(且删除中没有new参数,因为原来的参数也被删没了),new多用于更新
    使用时若要使用原来和新的参数则直接使用old.参数名new.参数名即可
    2、触发器不能触发自身,即本表触发本表,只能通过其他表触发本表或本表触发其他表

    示例

    • 1、当删除科目表(subject)中科目编号(SubjectNo)的时候将删除成绩表中此科目编号(SubjectNo)的一切成绩
      • 代码(在科目表的触发器定义中写入):
    BEGIN
    -- 删除成绩表中科目编号等于科目表中被删除的科目编号的所有成绩
    DELETE FROM `result` WHERE SubjectNo = old.SubjectNo;
    
    END
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 2、当在学生表中插入新信息时,会在年级表中插入年级名(GradeName),且被插入的年级名为学生表中插入的新学生名称(new.StudentName)
      • 代码(在学生表的触发器定义中写入):
    begin
    -- 年级表中插入年级名(GradeName),且被插入的年级名为学生表中插入的新学生名称(new.StudentName)
    INSERT INTO grade (GradeName) VALUES (new.StudentName);
    
    END
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    K8s小白?应用部署太难?看这篇就够了!
    JUC学习笔记——进程与线程
    Pycharm中6个常用插件推荐
    手把手带你从官网下载安装 Vivado
    Shiro入门(五)Shiro自定义Realm和加密算法
    Docker 常用命令大全
    (附源码)ssm码农论坛 毕业设计 231126
    SS-Model【5】:U-Net
    Lec14 File systems 笔记
    卡那霉素(Kanamycin偶联卵清白蛋白 (KAN-OVA)
  • 原文地址:https://blog.csdn.net/weixin_55452293/article/details/126749653