MYSQL存储过程和函数是数据库管理的强大工具,可以帮助用户实现复杂的数据操作,同时提高代码的复用性和数据库的性能。
一、存储过程和函数的概念
存储过程(stored procedures):一组预先封装编译好的SQL语句,理解成批处理语句。这些SQL语句 被编译并存储在数据库中,用户可以通过指定存储过程的名称并给出参数来执行调用。
函数(functions):类似于存储过程,但通常是用来执行计算并返回单个值的,在MYSQL中,函数必须返回一个值,而且只能有输入参数。
二、存储过程和函数的区别
(一)、返回值
存储过程可以有零个返回值,也可以有多个返回值;
函数有且仅有一个返回值。
(二)、调用方式
函数可以被嵌入到SQL语句中调用,如同其他内置函数一样;
存储过程必须通过CALL语句来调用。
(三)、用途
函数通常用于计算和处理数据,返回单一的结果;
存储过程更强大,可以执行一系列SQL语句进行更复杂的操作(如:适合做批量的插入和更新)。
(四)、参数
函数只支持输入参数;
存储过程可以有输入参数、输出参数和输入输出参数
三、存储过程和函数的优点
(一)提高性能:存储过程和函数是预编译的,可以减少SQL解析的时间,提高执行效率。
(二)减少网络交互:减少应用程序和数据库服务器之间的数据传输(数据更安全)。
(三)复用性和封装性:将复杂的逻辑业务封装在存储过程和函数中,简化应用开发。
(四)安全性:通过授权可控制对存储过程和函数的访问,增强数据的安全性。
四、存储过程和函数的创建和使用
(一)存储过程
1、创建语法
CREATE PROCEDURE 存储过程名(参数列表)
BEGIN
存储过程体(一组合法有效的SQL语句)
END
注意:
1 参数列表包含三部分(参数模式、参数名、参数类型)
2 参数模式:
IN:该参数作为入口(该参数需要调入方传入值)
OUT:该参数作为出口(该参数可以作为返回值)
INOUT:该参数既可以作为输入又可以作为输出(该参数既要传入值、又可以返回值)
3 如果存储过程仅仅只有一句话,BEGIN END可以省略
4 存储过程体中的每一条SQL语句必须加分号
5 避免混淆,存储过程体的结尾的结束标志分号可以换成其他符号(DELIMITER 结束)
DELIMITER $
2、调用语法
CALL 存储过名(实参列表);
3、删除语法
语法(一次只能删除一个存储过程)
DROP PROCEDURE 存储过程名;
4、查看语法
查看存储过程
# 查看数据库下的所有存储过程
select * from information_schema.ROUTINES where ROUTINE_SCHEMA = '数据库';
# 查看具体存储过程的创建语法
SHOW CREATE PROCEDU RE myp2;
5、案例
(1)空参列表
案例1、插入到admin表中三条记录
DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
INSERT INTO admin(username,`password`)
VALUES('li','2220'),('lishao','280'),('lixing','2220');
END $
CALL myp1()$
(2)创建带in模式参数的存储过程
案例2、创建存储过程实现根据女神名查询对应的男神信息
CREATE PROCEDOURE myp2(IN beautyName VARCHAR(20))
BEGIN
SELECT bo.*
FROM boys bo
RIGHT JOIN beauty b ON b.boyfriend_id=bo.id
WHERE b.name=beautyName;
END $
CALL myp2(‘柳岩’)$
出现报错Incorrect string value需要重新设置字符集(因为当前使用的是utf8更改成gbk就行了)
重新设置字符集 :set name gbk;
创建视图要在命令行下执行;
案例3、创建存储过程实现,用户是否登陆成功
CREATE PROCEDURE myp3(INT username VARCHAR(20),PASSWORD VARCHAR(20))
BEGIN
DECLARE result VARCHAR(20) DEFAULT''; #声明并初始化
SELECT COUNT(*) INTO result #赋值
FROM admin
WHERE admin.username = username
AND admin.password = PASSWORD
SELECT IF(result>0,'成功','失败') #使用
END $
CALL myp3('张飞','408')
(3)创建带out模式的存储过程
案例4、根据女神名,返回对应的男神名
DELIMITER $
CREATE PROCEDURE myp5(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20))
BEGIN
SELECT bo.boyName INTO boyName
FROM boys bo
JOIN beauty b
ON bo.id = b.boyfriend_id
WHERE b.`name` = beautyName;
END $
#调用
CALL myp5('小昭',@bName)$
SELECT @bNmae$
案例5、根据女神名返回对应的男神名和男神魅力值
CREATE PROCEDURE myp5(IN beautyName VARCHAR(20),OUT boyName
VARCHAR(20),OUT userCP INT)
BEGIN
SELECT bo.boyName INTO boyName,bo.userCP INTO userCP
FROM boys bo
JOIN beauty b
ON bo.id = b.boyfriend_id
WHERE b.`name` = beautyName;
END $
CALL myp5('小昭',@bName,$userCP)$
SELECT @bNmae,@userCP$
(4)创建带inout模式参数的存储过程
案例6、传入a和b两个值,最终a和b都翻倍并返回
CREATE PROCEDURE myp8(INOUT a INT,INOUT b INT)
BEGIN
SET a=a*2;
SET b=b*2
END $
SET @m=10;
SET @n=20;
CALL myp8(@m,@n)$
SELECT @m,@n;
(二)函数
1、创建语法
CREATE FUNCTION 函数名(参数列表) RETURN 返回类型
BEGIN
函数体
END
2、调用语法
SELECT 函数名(参数列表);
3、查看语法
方式一:
SHOW CREATE FUNCTION 函数名;
方式二、
在mysql库中proc表中能看到建立的函数
4、删除语法
DROP FUNCTION 函数名;
5、案例
1、无参有返回
案例1、返回公司的员工个数
CREATE FUNCTION myf1() RETURN INT
BEGIN
DECLARE c INT DEFAULT 0;#定义变量
SELECT COUNT(*) INTO c #赋值
FROM employees;
RETURN c;
END$2、有参有返回值
案例2、根据员工名,返回他的工资。
CREATE FUNCTION myf2(empName VARCHAR(20)) RETURN DOUBLE
BEGIN
SET @sal=0;#定义并初始化用户变量
SELECT salary INTO @sal #赋值
FROM employees
WHERE last_name=emplName;
RETURN @sal;
END$ SELECT myf2('K_ing')$
案例3、根据部门名,返回该部门的平均工资。
CREATE FUNCTION myf3(depName VARCHAR(20)) RETURN DOUBLE
BEGIN
DECLARE avg_sal DOUBLE;
SELECT AVG(salary) INTO avg_sal
FROM employees e
JOIN departments d ON d.department_id=e.department_id
WHERE department_name=depName
GROUP BY d.department_id;
RETURN avg_sal;
END$游标
游标(CURSOR)是用来存储查询结果集的数据类型 , 在存储过程和函数中可以使用游标对结果集进行循环的处理。游标的使用包括游标
的声明、OPEN、FETCH 和 CLOSE,其语法分别如下。声明游标
declare 游标名称 cursor for 查询语句;
打开游标
open 游标名称;
获取游标数据
fetch 游标名称 into 变量
关闭游标
close 游标名称;
案例、根据传入的参数uage,来查询用户表tb_user中,所有的用户年龄小于等于uage的用户姓名(name)和专业(profession),并将用户的姓名和专业插入到所创建的一张新表(id,name,perfession)中
逻辑:
A-声明游标,存储查询结果集
B-准备:创建表结构表
C-开启游标
D-获取游标中的数据
E-插入数据到新表中
F-关闭游标
create procedure p2(in usage int)
begin
declare uname varchar(100);
declare upro varchar(100);
declare u_cursor cursor for select name,perfession from tb_user where age <=uage;
drop table if exists tb_user_pro;
create table if exists tb_user_pro(
id int primary key auto_increment,
name varchar(100),
profession varchar(200)
);
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;
条件处理程序
create procedure p2(in usage int)
begin
declare uname varchar(100);
declare upro varchar(100);
declare u_cursor cursor for select name,perfession from tb_user where age <=uage;
declare exit handler for SQLSTATE '02000' close u_cursor;
drop table if exists tb_user_pro;
create table if exists tb_user_pro(
id int primary key auto_increment,
name varchar(100),
profession varchar(200)
);
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;
触发器
触发器是与表有关的数据库对象,指在 insert/update/delete 之前或之后,触发并执行触发器中定义的SQL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性 , 日志记录 , 数据校验等操作 。
使用别名 OLD 和 NEW 来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。现在触发器还只支持行级触发,不支持语句
级触发。
创建
create trigger 触发器名字
before/after insert/update/delete
on 表名 for fach row --行级触发器
begin
触发器语法;
end;
查看
show triggers;
删除
drop triggers 触发器名字;
案例、通过触发器记录 tb_user 表的数据变更日志,将变更日志插入到日志表user_logs中, 包含增加, 修改 , 删除 ;
create table user_logs(
id int not null auto_increment,
operation varchar(20) not null comment '操作类型,insert/update/delete',
operate_time datetime not null comment '操作时间',
operate_id int not null comment '操作时间',
operate_params varchars(500) comment '操作参数'),
primary key(‘id’)
)engine=innodb default charset=utf-8;
insert
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('插id',new.id,''))