MySQL【触发器、存储过程、函数、范式】

day53

MySQL

触发器

创建触发器:(before : 前置触发器、after :后置触发器)

语法:
delimiter xx 指定分隔符xx

create trigger 触发器名 [before | after] 触发事件 on 表名 for each row 执行语句

  begin

   多条执行语句

  end 加上 “结束符xx”

delimiter ;还原分隔符未;

注意:

由某个事件去触发某个操作,这些事件有:insert、update、delete语句;

new.字段:当前写法可以获得添加语句字段对应的值

old.字段:当前写法可以获得删除语句字段对应的值

在MySQL中,DELIMITER是用来指定SQL语句中的语句分隔符的关键字。

默认情况下,分号(;)作为语句的结束符号。

当在一个语句中包含了多个语句,比如在创建存储过程、触发器等时,如果直接使用分号作为结束符号,会导致MySQL将整个语句作为一个语句进行解析,从而导致语法错误。所以才有指定分隔符,又还原这个操作。

补充解释:

数据添加后相应的表数据更新的需求,每次用更新语句十分不便
ps:update class set sum = sum+1 where id =1;
所以使用触发器
begin end类似于{},有点像函数,多个语句时使用,单个可不用
对于前触发器,例如删除操作,要在删除之前才拿得到,如果删除之后再操作不行,因为数据已经被删了
在第一次操作之后,再进行重复操作不会再触发触发器

# 触发器

# 创建场景 ----------------------------------------------------------------------------

# 创建学科表,并添加数据
CREATE TABLE course(
	id INT(3) PRIMARY KEY auto_increment,
	name VARCHAR(32),
	sum INT(3) DEFAULT 0
)
INSERT INTO course(name) VALUES('JavaEE');
INSERT INTO course(name) VALUES('Python');
INSERT INTO course(name) VALUES('HTML');

# 创建班级表,并添加数据
CREATE TABLE class(
	id INT(3) PRIMARY KEY auto_increment,
	name VARCHAR(32),
	sum INT(3) DEFAULT 0
)
INSERT INTO class(name) VALUES('01JavaEE');
INSERT INTO class(name) VALUES('02JavaEE');
INSERT INTO class(name) VALUES('01Python');
INSERT INTO class(name) VALUES('02Python');
INSERT INTO class(name) VALUES('01HTML');
INSERT INTO class(name) VALUES('02HTML');

# 创建学生表
CREATE TABLE student(
	id INT(3) PRIMARY KEY auto_increment,
	name VARCHAR(32),
	class_id INT(3),
	course_id INT(3)
)

# ------------------------------------------------------------------------------------------------------

# 需求:添加学生,并更新班级表和学科表的数据

# 创建触发器(添加学生数据之后,就会触发班级表和学科表更新数据的操作)
# delimiter xx - 设置SQL命令的结束符
# trigger - 触发器
# after - 后置触发
delimiter xx
create trigger tri01 after insert on student for each row
	BEGIN
		UPDATE class SET sum=sum+1 WHERE id=new.class_id;
		UPDATE course SET sum=sum+1 WHERE id=new.course_id;
	END xx
delimiter ;

INSERT INTO student(name,class_id,course_id) VALUES('小王',1,1);
INSERT INTO student(name,class_id,course_id) VALUES('小马',1,1);
INSERT INTO student(name,class_id,course_id) VALUES('小李',2,1);
INSERT INTO student(name,class_id,course_id) VALUES('麻生希',3,2);
INSERT INTO student(name,class_id,course_id) VALUES('椎名空',4,2);

# ------------------------------------------------------------------------------------------------------

# 需求:删除学生,并更新班级表和学科表的数据

# 创建触发器(删除学生数据之前,就会触发班级表和学科表更新数据的操作)
delimiter xx
create trigger tri02 before delete on student for each row
	BEGIN
		UPDATE class SET sum=sum-1 WHERE id=old.class_id;
		UPDATE course SET sum=sum-1 WHERE id=old.course_id;
	END xx
delimiter ;

DELETE FROM student WHERE id = 2;

# ------------------------------------------------------------------------------------------------------

# 删除触发器
DROP TRIGGER tri01;
DROP TRIGGER tri02;


运行分析:
后触发器
前触发器

存储过程

理解:类似java里面的方法,但无返回值,有返回参数

参数列表

输入类型的参数 -- in

输出类型的参数 -- out

输入输出类型的参数 -- inout

注意:

对于传入的参数,要与本身参数区分,识别不了会报错

返回参数,需要用到传出参数,into传出参数

调用存储过程,有两种

  1. 一种直接调用查就会直接打印结果
  2. 另一种,拿到参数变量值,不会立即打印结果,还可以进行再查操作

对于传入参数与传出参数类型相同,可用传入传出参数,相当于简写

# 存储过程
# 注意:类似于Java里的方法

# 创建场景 ----------------------------------------------------------------------------

# 创建学生表,并添加数据
CREATE TABLE student(
	id INT(3) PRIMARY KEY auto_increment,
	name VARCHAR(32),
	sex VARCHAR(32),
	age INT(3),
	salary FLOAT(8,2),
	course VARCHAR(32)
)
INSERT INTO student(name,sex,age,salary,course) VALUES('奇男子','男',23,10000,'Java');
INSERT INTO student(name,sex,age,salary,course) VALUES('小兰','男',20,12000,'Java');
INSERT INTO student(name,sex,age,salary,course) VALUES('奇女子','女',19,17000,'Java');
INSERT INTO student(name,sex,age,salary,course) VALUES('刘德华','男',21,15000,'Java');
INSERT INTO student(name,sex,age,salary,course) VALUES('马德华','男',27,10000,'Java');
INSERT INTO student(name,sex,age,salary,course) VALUES('霍建华','男',19,12000,'Java');
INSERT INTO student(name,sex,age,salary,course) VALUES('华晨宇','男',32,5000,'Python');
INSERT INTO student(name,sex,age,salary,course) VALUES('黄日华','男',45,4000,'Python');
INSERT INTO student(name,sex,age,salary,course) VALUES('任达华','男',28,7000,'Python');
INSERT INTO student(name,sex,age,salary,course) VALUES('周华健','男',30,8000,'Python');
INSERT INTO student(name,sex,age,salary,course) VALUES('欧阳震华','男',23,12000,'Python');
INSERT INTO student(name,sex,age,salary,course) VALUES('麻生希','女',30,7000,'HTML');
INSERT INTO student(name,sex,age,salary,course) VALUES('椎名空','女',23,6000,'HTML');
INSERT INTO student(name,sex,age,salary,course) VALUES('水野朝阳','女',28,8000,'HTML');

# ----------------------------------------------------------------------------

# 最简单的存储过程
# 查询学生表和用户表里的数据
delimiter xx
CREATE PROCEDURE pro01()
	BEGIN
		SELECT * FROM student;
		SELECT * FROM user;
	END xx
delimiter ;

# 调用存储过程
CALL pro01();

# ----------------------------------------------------------------------------

# SQL中存储过程 与 Java中方法 的区别
# Java方法中的参数指的是外界传入到方法内部的数据,返回值指定是方法结束后返回的具体数据
# SQL存储过程中没有返回值,但是有返回参数

# 存储过程中参数的分类:
#		in - 传入参数
#		out - 传出参数
#		inout - 传入传出参数

# ----------------------------------------------------------------------------

# 需求:创建存储过程,传入学生id,查询出学生姓名
delimiter xx
CREATE PROCEDURE pro02(IN s_id INT(3))
	BEGIN
		SELECT name FROM student WHERE id=s_id;
	END xx
delimiter ;

# 调用存储过程
CALL pro02(2);

# ----------------------------------------------------------------------------

# 需求:创建存储过程,传入学生id,返回学生姓名
delimiter xx
CREATE PROCEDURE pro03(IN s_id INT(3),OUT s_name VARCHAR(32))
	BEGIN
		SELECT name INTO s_name FROM student WHERE id=s_id;
	END xx
delimiter ;

# 调用存储过程
CALL pro03(3,@s_name);
SELECT @s_name;

# ----------------------------------------------------------------------------

# 需求:创建存储过程,传入学生id,返回学生年龄
delimiter xx
CREATE PROCEDURE pro04(INOUT param INT(3))
	BEGIN
		SELECT age INTO param FROM student WHERE id=param;
	END xx
delimiter ;

# 调用存储过程
SET @param = 3;
CALL pro04(@param);
SELECT @param;

# ----------------------------------------------------------------------------

# 删除存储过程
DROP PROCEDURE pro01;
DROP PROCEDURE pro02;
DROP PROCEDURE pro03;
DROP PROCEDURE pro04;

运行分析:

调用存储过程方式1

调用存储过程p1方式1
存储过程p2

调用存储过程方式2

调用存储过程p3方式2
存储过程p4

函数

预定义函数

数学函数:

绝对值函数:select abs(字段) from 表 ps:此函数指的是求绝对值

平方根函数:select sqrt(9) ps:得到的值为3

求余函数:select mod(10,3) / select 10%3 ps:得到的值为1

随机函数:select rand() ps:得到的值为0~1

幂运算函数:select pow(10,2) ps:10的2次方

字符串函数:

长度函数:select length(‘内容’)

合并函数:select concat(’hello’,’world’)

截取字符串函数:select substring(字段,start,end)

日期/时间函数:

​ 当前日期函数:curdate()

​ 当前时间函数:curtime()

​ 当前日期+时间函数:now()

​ 年函数:year(now())

​ 月函数:month(now())

​ 日函数:dayofmonth(now())

​ 时函数:hour(now())

​ 分函数:minute(now())

​ 秒函数:second(now())

​ 时间格式函数:年月日时分秒‘别名

注意:

当然对于在Navbbicat的 函数里可以看到是否删除

# 预定义函数
# 理解:MySQL给我们提供的函数
# 注意:函数必须有返回值

# 数学类函数 -----------------------------------------------------
SELECT ABS(-100);# 求绝对值
SELECT sqrt(9);  # 求平方根
SELECT mod(10,3);# 求余数
SELECT pow(2,3); # 求次方
SELECT rand();# 求随机值

# 字符串类函数 -----------------------------------------------------

SELECT CONCAT("用良心做教育","做真实的自己");# 拼接字符串
SELECT SUBSTR("用良心做教育",2,2);# 截取字符串(目标字符串,第几个字符,截取长度)
SELECT length("用良心做教育");# 获取长度(字节)

# 日期时间类函数 -----------------------------------------------------

SELECT now();# 获取当前日期时间
SELECT YEAR(NOW());# 获取年
SELECT MONTH(NOW());# 获取月
SELECT DAYOFMONTH(NOW());# 获取日
SELECT HOUR(NOW());# 获取时
SELECT MINUTE(NOW());# 获取分
SELECT SECOND(NOW());# 获取秒
SELECT DATE_FORMAT(NOW(),"%Y年%m月%d日 %H时%i分%s秒");

运行分析:
预定义函数2
预定义函数3

自定义函数

返回值,需要一个变量去接查到的数据,再返回此变量
对于5.7版本,5.5版本之类不加关键字就可运行,8.0必须加不然运行即报错
加了关键字DETERMINISTIC就认为它是一个函数

语法:
create function 函数名([参数列表]) returns 数据类型 DETERMINISTIC
begin
      sql语句;
      return 值;
end
# 自定义函数
# 注意:MySQL的函数必须有返回值

# 需求:创建一个函数,传入学生id,返回学生信息

delimiter xx
CREATE FUNCTION fun(s_id INT(3)) RETURNS VARCHAR(32) DETERMINISTIC
	BEGIN
	
		DECLARE s_name VARCHAR(32);
		SELECT name INTO s_name FROM student WHERE id=s_id;
		RETURN s_name;
	END xx
delimiter ;

 # 调用函数
 SELECT fun(3);
 
 # 删除函数:
DROP function fun;

运行分析:
自定义函数

范式

第一范式:理解为所有数据集中在一张表,存在多种问题
第二范式:简单分表,解决数据冗余,但一对多种关系出现多个数据不可避免
第三范式:再细化分表,第一范式存在问题全部解决;但表就会很多,需要多表联合查询,效率很低
反范式:就是把第三范式细化的多张表,又重新融合一些表,就会出现数据冗余,这里就考验程序员的能力考虑融合
空间换时间:对于现在的空间大可不考虑就得考虑时间
对于第三范式和反范式之间选择:根据具体项目而定,哪些该融合,哪些该细分;就简单说用的少的表可以融合到其他表

下面以表的形式理解

第一范式

第一范式

第二范式

第二范式

第三范式

第三范式

反范式

反范式

小结:

  1. 触发器
  2. 存储过程
  3. 函数
  4. 范式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/732201.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

maven:中央仓库验证方式改变:401 Content access is protected by token

前几天向maven中央仓库发布版本,执行上传命令mvn release:perform时报错了: [ERROR] Failed to execute goal org.sonatype.plugins:nexus-staging-maven-plugin:1.6.13:deploy (injected-nexus-deploy) on project xxxxx: Failed to deploy artifacts: …

智慧互联,Vatee万腾平台引领新潮流

在数字化、智能化的新时代,智慧互联正成为推动社会进步的重要力量。在这一潮流中,Vatee万腾平台凭借其卓越的技术实力和创新理念,正引领着新潮流,将智慧互联的理念融入生活的方方面面。 Vatee万腾平台是一个以大数据、云计算、人工…

C#利用SignalR实现通信事例Demo

1.服务端安装SignalR的Nuget包 dotnet add package Microsoft.AspNet.SignalR --version 2.4.3 2.接下来,创建一个ChatHub类,它是SignalR通信的核心: using Microsoft.AspNetCore.SignalR;public class ChatHub : Hub {public static Dict…

聊聊 C# dynamic 类型,并分享一个将 dynamic 类型变量转为其它类型的技巧和实例

前言 dynamic 是一种有别于传统变量类型的动态类型声明,刚开始接触可能在理解上会有些困难,可以简单地把它理解为一个盲盒,你可以任意猜测盒子有什么东西,并认为这些东西真正存在而进行处理,等到真正打开时&#xff0…

文章自动生成器,在线AI写作工具

随着人工智能AI技术的发展,AI技术被应用到越来越多的场景。对于需要创作内容的同学来说,AI写作-文章内容自动生成器是一个非常好的辅助工具。AI写作工具可以提升我们的创作效率,快速的生成文章,然后在根据需求进行调整修改即可。下…

语法制导的翻译和属性文法

属性的分类 1.综合属性 重写规则(产生式)左部符号的属性是综合属性。一个结点相应文法符号的属性值通过语法分析树中它的子节点的属性之值计算(自底向上) 2.继承属性 出现在重写规则右部的符号的属性。一个结点相应文法符号的属性…

概念描述——TCP/IP模型中的两个重要分界线

TCP/IP模型中的两个重要分界线 协议的层次概念包含了两个也许不太明显的分界线,一个是协议地址分界线,区分出高层与低层寻址操作;另一个是操作系统分界线,它把系统与应用程序区分开来。 高层协议地址界限 当我们看到TCP/P软件的…

没等来百度惊艳的All in AI,却等来了国产之光的盘古大模型 5.0

6月21日,华为开发者大会(HDC 2024)在广东东莞正式开幕。盘古大模型5.0的更新,也是此次HDC2024的另一项重头戏。在过去的一年中,盘古大模型正在疯狂向各行各业渗透。 此次,华为方面展示了他们在具身智能、医…

【面向对象】复习(二)

内存对齐 class A{ static int a; } int main(){ A obj; cout<<sizeof(obj); } 在你的代码中&#xff0c;class A 包含一个静态成员变量 a。静态成员变量不属于类的任何特定实例&#xff0c;而是属于整个类。因此&#xff0c;在计算类的实例大小时&#xff0c;静态…

C语言入门系列:指针入门(超详细)

文章目录 一&#xff0c;什么是指针1&#xff0c;内存2&#xff0c;指针是什么&#xff1f; 二&#xff0c;指针的声明1&#xff0c;声明指针类型变量2&#xff0c;二级指针 三&#xff0c;指针的计算1&#xff0c;两个指针运算符1.1 *运算符1.2 & 运算符1.3 &运算符与…

状态压缩DP——AcWing 291. 蒙德里安的梦想

状态压缩DP 定义 状态压缩DP是一种利用二进制数来表示状态的动态规划算法。它通过将状态压缩成一个整数&#xff0c;从而减少状态数量&#xff0c;提高算法效率。 运用情况 状态压缩DP通常用于解决具有状态转移和最优解性质的问题&#xff0c;例如组合优化、图论、游戏等问…

python-邮票组合问题

[题目描述] 某人有四张3分的邮票和三张5分的邮票&#xff0c;用这些邮票中的一张或若干张可以得到多少种不同的邮资&#xff1f;输入格式&#xff1a; 此题无输入。输出格式&#xff1a; 输出可以得到不同邮资的数量。 样例输入 无样例输出 19数据范围&#xff1a; 对于100%的…

华为---RIP路由协议的汇总

8.3 RIP路由协议的汇总 8.3.1 原理概述 当网络中路由器的路由条目非常多时&#xff0c;可以通过路由汇总(又称路由汇聚或路由聚合)来减少路由条目数&#xff0c;加快路由收敛时间和增强网络稳定性。路由汇总的原理是&#xff0c;同一个自然网段内的不同子网的路由在向外(其他…

与Vatee万腾平台同行,共创智能未来

在科技日新月异的今天&#xff0c;智能化已成为推动社会进步的重要力量。Vatee万腾平台&#xff0c;作为这一浪潮中的佼佼者&#xff0c;正以其独特的创新力和前瞻的视野&#xff0c;引领我们迈向智能未来。与Vatee万腾平台同行&#xff0c;我们不仅能享受到科技带来的便捷与舒…

[最新教程]Claude Sonnet 3.5注册方法详细步骤分享,新手小白收藏,文末免费送已注册的Claude账号

一.Claude sonnet 3.5大模型面世 6月21日&#xff0c;被称为“OpenAI 最强竞对”的大模型公司 Anthropic 发布了 Claude 3.5 系列模型中的第一个版本——Claude 3.5 Sonnet。 Anthropic 在官方博客中表示&#xff0c;Claude 3.5 Sonnet 提高了智能化的行业标准&#xff0c;在…

传统图像特征描述及提取方法

目录 一、图像特征描述 二、图像特征的分类 2.1 图像的点、线、面特征 2.2 图像的纹理形状特征 2.3 图像颜色特征 2.4图像的统计特征 三、图像特征提取的评价 一、图像特征描述 图像特征是一幅图像区别于另一幅图像最基本的特征,是其可以作为标志性的属性。 图像特征分为…

2024 年解锁 Android 手机的 7 种简便方法

您是否忘记了 Android 手机的 Android 锁屏密码&#xff0c;并且您的手机已被锁定&#xff1f;您需要使用锁屏解锁 Android 手机&#xff1f;别担心&#xff0c;您不是唯一一个忘记密码的人。我将向您展示如何解锁 Android 手机的锁屏。 密码 PIN 可保护您的 Android 手机和 G…

高考志愿填报,如何权衡学校和专业?

高考是人生的分水岭&#xff0c;成绩好的学生能就读更好的大学&#xff0c;获得更多的学习资源&#xff0c;但也有一些同学即使凭借高分数进入了高校&#xff0c;专业的学习过程却不尽如人意&#xff0c;他们也没有将100%的精力投入到专业学习当中。 无论高考结束之后获得了多…

python--fasApi学习(Dash+FastAPI框架)

在学习fastApi 框架时&#xff0c;发现了一个好用的框架&#xff0c;参考&#xff1a; 博客参考&#xff1a; https://blog.csdn.net/gitblog_00002/article/details/137331157下载文档并部署&#xff1a; 下载代码&#xff1a; git clone https://gitee.com/insistence2022/…

LeetCode 1-两数之和

LeetCode第1题 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现…