数据库——MySQL存储过程、函数和流程控制结构

一、存储过程

1. 定义

  • 一组经过预先编译的sql语句的集合,可理解为批处理语句

2. 好处

  • 提高了sql语句的重用性
  • 简化操作,减少了开发程序员的压力
  • 减少了编译次数和数据库服务器的连接次数,提高效率

3. 创建语法

每条sql语句结尾必须要加分号

create procedure 存储过程名(in|out|inout 参数名 参数类型)
begin
	存储过程体;
end

/* 
1.参数列表(in|out|inout 参数名 参数类型)
1.1 参数模式
in:该参数只能作为输入(该参数不能做返回值),默认是in
out:该参数只能作为输出(该参数只能做返回值)
inout:既能做输入又能做输出
1.2 参数名
1.3 参数类型

2.存储过程体
2.1 存储过程体中可以有多条sql语句,如果仅仅一条sql语句,则可以省略begin end 
2.2 存储过程体中每条sql语句结尾必须要加分号
2.3 存储过程体的结尾可以使用delimiter设置

3.示例:
delimiter $
CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名  参数类型,...)
BEGIN
	sql语句1;
	sql语句2;
END $
*/

类似于

修饰符 返回类型 方法名(参数类型 参数名,...)
{
	方法体;
}

4. 调用语法

call 存储过程名(实参列表);

5. 示例

5.1 空参的存储过程

案例:插入数据

mysql> select * from stu;
+----+------+
| id | name |
+----+------+
|  1 | a    |
|  2 | b    |
|  3 | c    |
+----+------+
3 rows in set (0.00 sec)

mysql> DELIMITER $
mysql> CREATE PROCEDURE pro1()
    -> BEGIN
    -> INSERT INTO stu(NAME)
    -> VALUES('d'),('e'),('f'),('g');
    -> END $
Query OK, 0 rows affected (0.27 sec)

mysql> call pro1();
    -> $
Query OK, 4 rows affected (0.15 sec)

mysql> select * from stu;
    -> $
+----+------+
| id | name |
+----+------+
|  1 | a    |
|  2 | b    |
|  3 | c    |
|  4 | d    |
|  5 | e    |
|  6 | f    |
|  7 | g    |
+----+------+
7 rows in set (0.00 sec)

5.2 带in模式参数的存储过程

案例:创建存储过程,根据部门名称查询包含的员工信息

DROP TABLE IF EXISTS emp;
CREATE TABLE emp
(
	id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
	ename VARCHAR(50),
	did INT
);
INSERT INTO emp(ename,did) VALUES ('a',1),('b',2),('c',NULL);
SELECT * FROM emp;
+----+-------+------+
| id | ename | did  |
+----+-------+------+
|  1 | a     |    1 |
|  2 | b     |    2 |
|  3 | c     | NULL |
+----+-------+------+

DROP TABLE IF EXISTS dept;
CREATE TABLE dept
(
	id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
	dname VARCHAR(50)
);
INSERT INTO dept(dname) VALUES ('dep1'),('dep2'),('dep3');
SELECT * FROM dept;
+----+-------+
| id | dname |
+----+-------+
|  1 | dep1  |
|  2 | dep2  |
|  3 | dep3  |
+----+-------+

CREATE PROCEDURE pro2(IN dname VARCHAR(50))
BEGIN
	SELECT e.id,e.ename,e.did,d.dname 
	FROM dept d
	RIGHT JOIN emp e
	ON e.did=d.id
	WHERE d.dname=dname;
END $
call pro2('dep2');$
+----+-------+------+-------+
| id | ename | did  | dname |
+----+-------+------+-------+
|  2 | b     |    2 | dep2  |
+----+-------+------+-------+

案例:创建存储过程,查询有部门信息的员工个数

# 数据字段同上
CREATE PROCEDURE pro3(IN did INT)
BEGIN
	DECLARE result INT DEFAULT 0;
	
	SELECT COUNT(*) 
	FROM emp e
	WHERE e.did=did;
	
	SELECT result;	
END $

CALL pro3('2')$

5.3 带out模式参数的存储过程

案例:根据员工姓名返回部门名称

CREATE PROCEDURE pro4(IN ename VARCHAR(20),OUT dname VARCHAR(20))
BEGIN
	SELECT d.dname INTO dname
	FROM dept d
	INNER JOIN emp e 
	ON e.did=d.id
	WHERE e.ename=ename;	
END $

CALL pro4('b',@name)$
SELECT @name$

5.4 带inout模式参数的存储过程

案例:将a员工姓名修改为姓名+部门名

+------+-------+------+----+-------+
| id   | ename | did  | id | dname |
+------+-------+------+----+-------+
|    1 | a     |    1 |  1 | dep1  |
|    2 | b     |    2 |  2 | dep2  |
| NULL | NULL  | NULL |  3 | dep3  |
+------+-------+------+----+-------+
CREATE PROCEDURE pro5(INOUT ename VARCHAR(20))
BEGIN
	SELECT CONCAT(d.dname,'-',e.ename) INTO ename
	FROM emp e
	RIGHT JOIN dept d 
	ON e.did=d.id
	WHERE e.ename=ename;	
END $
# 一定要新定义一个变量
set @x='b'$
call pro5(@x)$
select @x$
+--------+
| @x     |
+--------+
| dep2-b |
+--------+

6. 删除语法

drop PROCEDURE 存储过程名;

7. 查看存储结构的信息

show create PROCEDURE 存储过程名;

二、函数

1. 和存储过程的区别

区别存储过程函数
返回值个数0个或多个1个
适用范围批量插入、更新处理数据,拿到返回结果

2. 创建语法

CREATE FUNCTION 函数名(参数名 参数类型,...) RETURNS 返回类型
BEGIN
	函数体
END
# 参数列表:参数名,参数类型
# 函数体只有一句话,可以省略begin end
# 使用delimiter设置结束标志

3. 调用语法

SELECT 函数名(实参列表);

4. 示例

4.1 无参函数

set global log_bin_trust_function_creators=TRUE $
CREATE FUNCTION func1() RETURNS INT
BEGIN 
	DECLARE i INT DEFAULT 0; # 定义局部变量
	SELECT COUNT(*) INTO i FROM emp; # 赋值
	RETURN i;
END $
select func1() $
+---------+
| func1() |
+---------+
|       3 |
+---------+

4.2 有参函数

案例:根据员工姓名返回所属的部门名称

+----+-------+------+-------+
| id | ename | did  | dname |
+----+-------+------+-------+
|  1 | a     |    1 | dep1  |
|  2 | b     |    2 | dep2  |
|  3 | c     | NULL | NULL  |
+----+-------+------+-------+
CREATE FUNCTION func2(ename varchar(20)) RETURNS varchar(20)
BEGIN 
	set @dname = '';  # 也可以定义用户变量
	SELECT d.dname into @dname
	from emp e
	left join dept d
	ON e.did=d.id
	WHERE e.ename=ename;  # 赋值
	RETURN @dname;
END $
select func2('b') $
+------------+
| func2('b') |
+------------+
| dep2       |
+------------+

5. 查看函数

show create function 函数名;

6. 删除函数

drop function 函数名;

三、流程控制结构

1. 分支结构

1.1 if语句

  • 特点:可以用在任何位置
  • 语法
if(表达式1,表达式2,表达式3)
  • 执行顺序

如果表达式1成立,则返回表达式2的值,否则返回表达式3的值

1.2 if…else if语句

  • 特点:只能用在begin end中
  • 语法
if 情况1 then 语句1;
elseif 情况2 then 语句2;
...
else 语句n;
end if;

1.3 case语句

  • 特点
    • 如果作为表达式,嵌套在其他语句中使用,则可以放在任何地方
    • 如果作为独立的语句去使用,则只能放在begin end中
    • else可以省略,如果省略else且所有when条件都不满足,返回null
  • 语法
# 情况一:类似于switch,一般用于实现等值判断
case 变量、表达式、字段
when1 then 结果1或语句1;(如果是语句,需要加分号) 
when2 then 结果2或语句2;(如果是语句,需要加分号)
...
else 结果n或语句n(如果是语句,需要加分号)
endcase】(如果是放在begin end中需要加上case,如果放在select后面不需要)

# 情况二:类似于多重if,一般用于实现区间判断
case 
when 条件1 then 结果1或语句1(如果是语句,需要加分号) 
when 条件2 then 结果2或语句2(如果是语句,需要加分号)
...
else 结果n或语句n(如果是语句,需要加分号)
endcase】(如果是放在begin end中需要加上case,如果放在select后面不需要)

1.4 示例

案例1:创建存储过程,将输入的百分制成绩转换成字母制成绩

CREATE PROCEDURE test_case1(IN score INT)
BEGIN
	CASE
	WHEN score>=90 AND score <=100 THEN SELECT 'A';
	WHEN score>=80 THEN SELECT 'B';
	WHEN score>=70 THEN SELECT 'C';
	END CASE;# 在begin end中需要添加end case
END $
CALL test_case1(95) $

案例2:将数据表中的百分制成绩转换成字母制成绩

SELECT stu.`id`,stu.`name`,stu.`score`,
CASE
	WHEN score >=90 AND score <=100 THEN 'A'
	WHEN score >=80 AND score <=90 THEN 'B'
	WHEN score >=70 AND score <=80 THEN 'C'
	WHEN score >=60 AND score <=70 THEN 'D'
	ELSE 'E'
END AS scorelevel # 放在select中不需要 end case
FROM stu;
+----+------+-------+------------+
| id | name | score | scorelevel |
+----+------+-------+------------+
|  1 | a    |    95 | A          |
|  2 | b    |    80 | B          |
|  3 | c    |    86 | B          |
|  4 | d    |    72 | C          |
|  5 | e    |    99 | A          |
|  6 | f    |    83 | B          |
|  7 | g    |    65 | D          |
+----+------+-------+------------+

2. 循环结构

2.1 分类

  • While
[标签:] while 循环条件 do
	循环体;
end while [标签];
  • Loop:模拟死循环
[标签:] loop 
	循环体;
end loop [标签];
  • Repeat:类似do while
[标签:] repeat
	循环体;
until 结束循环的条件
end while [标签];

2.2 循环控制

  • iterate:结束本次循环,继续下一次
  • leave:跳出,结束循环

2.3 示例

案例1:批量插入数据,没有添加循环控制语句

//java
int i=1;
while (i<=n){
	i++;
	insert...
}
# sql
create procedure pro_while1(in insertcount int)
begin
	declare i int default 1;
	while i<=insertcount do
		insert into emp(ename,did) values(concat('emp',i),1);
		set i=i+1;
	end while;
end $
call pro_while1(100) $

案例2:添加leave语句,批量插入数据,如果数据大于20就停止

涉及到循环控制的,必须加标签

//java
int i=0;
while (i<=n){
	insert...
	if(i>=20) break;
	i++;
}
create procedure pro_while2(in insertcount int)
begin
	declare i int default 1;
	a:while i<=insertcount do
		insert into emp(ename,did) values(concat('emp',i),1);
		if i>=20 then leave a;
		end if;
		set i=i+1;
	end while a;
end $
call pro_while2(100) $

案例3:添加iterate语句,批量插入数据,只插入偶数次

//java
int i=0;
while (i<=n){
	i++;
	if(i%2==0) continue;
	insert...
}
create procedure pro_while3(in insertcount int)
begin
	declare i int default 0;
	a:while i<=insertcount do
		set i=i+1;
		if mod(i,2)!=0  then iterate a;
		end if;
		insert into emp(ename,did) values(concat('emp',i),1);
	end while a;
end $
call pro_while3(100) $
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值