目录
一、实验目的与要求:
二、实验内容:
三、实验小结
实验中涉及到的数据及内容:数据库MySQL实验_Fxrain的博客-CSDN博客
一、实验目的与要求:
1、掌握存储过程的工作原理、定义及操作方法
2、掌握函数的工作原理、定义及操作方法
3、掌握游标的工作原理、定义及操作方法
二、实验内容:
1. 创建存储过程,用来自动统计给定订单号的订单总金额
源码:
1创建函数
CREATE DEFINER=`root`@`localhost` FUNCTION `summoney`(s int) RETURNS decimal(8,2)
READS SQL DATA
BEGIN
RETURN (
SELECT SUM(quantity*item_price)
FROM orderitems
where o_num=s
);
END
2测试函数
select summoney(50010);
运行测试结果截图(输入订单号'50010'测试结果):
2.创建存储过程,自动搜索并添加客户及供货商帐号信息到新建的用户信息表。
①增加用户表信息user
表1 user表结构
字段名 | 字段说明 | 数据类型 | 主键 | 外键 | 非空 | 唯一 | 自增 |
id | ID号 | int (11) | Y | N | Y | Y | Y |
u_id | 用户编号 | int (11) | N | N | Y | Y | N |
pwd | 密码 | blob | N | N | Y | N | N |
remark | 注释 | varchar (255) | N | N | Y | N | N |
源码:
CREATE TABLE user(
id INT(11) not NULL UNIQUE AUTO_INCREMENT,
u_id INT(11) not NULL UNIQUE,
pwd BLOB not NULL,
remark VARCHAR(255) not NULL,
PRIMARY KEY(id)
) COMMENT '';
运行结果图:
② 创建两个存储过程,分别把客户表的c_id和供货商表s_id的字段自动添加到用户信息表,补充pwd和remark字段。
要求:id字段自动增加,u_id 字段即客户或供货商的编号,pwd字段用AES_ENCRYPT函数加密,密码统一设置为用户编号u_id的值连接123456(如在当前表中u_id为10001,则其密码是10001123456),密钥是'hello'; remark字段内容是‘customer'或'supplier’
源码:
添加客户表帐号:
1创建存储过程
CREATE DEFINER=`root`@`localhost` PROCEDURE `customers_users`()
BEGIN
DECLARE label INT;
DECLARE u_id INT(11);
DECLARE user_cur CURSOR for SELECT c_id from customers;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET label=1;
SET label=0;
OPEN user_cur;
FETCH NEXT FROM user_cur INTO u_id;
WHILE(label=0) DO
insert into `user`(u_id,pwd,remark) VALUES(u_id,AES_ENCRYPT(CONCAT(u_id,'123456'),'hello'),'customer');
FETCH NEXT FROM user_cur INTO u_id;
END WHILE;
CLOSE user_cur;
END
2测试procedure
CALL customers_users();
运行测试结果截图:
添加供货商帐号:
1创建存储过程
CREATE DEFINER=`root`@`localhost` PROCEDURE `suppliers_users`()
BEGIN
DECLARE label INT;
DECLARE u_id INT(11);
DECLARE use_cur CURSOR FOR SELECT s_id FROM suppliers;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET label=1;
SET label=0;
OPEN use_cur;
FETCH NEXT FROM use_cur INTO u_id;
WHILE (label=0) DO
INSERT INTO `user`(u_id,pwd,remark) VALUES (u_id,AES_ENCRYPT(CONCAT(u_id,’123456’),'hello'),'supplier');
FETCH NEXT FROM use_cur INTO u_id;
END WHILE;
CLOSE use_cur;
END
2测试代码
CALL suppliers_users();
运行测试结果截图:
3.创建存储过程或函数来批量修正订单详情表orderitems中的水果价格与水果表fruits中的价格一致。
提示:用游标
源码:
1创建set_name过程
CREATE DEFINER=`root`@`localhost` PROCEDURE `set_same`()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE field_value decimal(8,2);
DECLARE label CHAR(10);
DECLARE cur CURSOR FOR SELECT f_price,f_id FROM fruits;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=TRUE;
OPEN cur;
#FETCH NEXT FROM cur INTO field_value,label;
WHILE(done=FALSE) DO
UPDATE orderitems SET orderitems.item_price=field_value WHERE orderitems.f_id = label;
FETCH NEXT FROM cur INTO field_value,label;
END WHILE;
CLOSE cur;
END
2测试代码:
CALL set_same();
运行测试结果截图:
下图分别为fruits表格和orderitems表格
三、实验小结
1.实验中遇到的问题及解决过程
问题一:在计算订单总金额时使用函数计算的订单总价与实际不符
计算得到的:269
实际值:268.80
解决过程:函数最后应返回decimal值,而不是int值
问题二:在创建procedure时无法运行整个过程
解决过程:不使用LOOP循环,改为do while循环
问题三:在创建user表格时,密码应该为用户编号u_id的值连接123456(如在当前表中u_id为10001,则其密码是10001123456),而代码中直接使用u_id+123456则会导致密码不是10001123456,而是10001+123456
解决过程:不能使用u_id+123456,而应该通过CONCAT把u_id和123456相连接。
问题四:将fruits表格中的f_price与orderitems表格中的item_price对应,即根据orderitems表格中的数据修改fruits表格,不符合逻辑关系。
解决过程:在循环中应该更新orderitems表格使orderitems表格中的数值与fruits中的数值相同。
- 实验中产生的错误及原因分析
错误一:在函数中使用两个return
原因分析:一个存储过程不能使用两个及两个以上的return
错误二:如以下代码所示,在更新orderitems表格时需要有条件,即orderitems.f_id=fruits.f_id,但是测试时orderitems表格中数值都相同
CREATE DEFINER=`root`@`localhost` PROCEDURE `set_same`()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE field_value decimal(8,2);
DECLARE cur CURSOR FOR SELECT f_price FROM fruits;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=TRUE;
OPEN cur;
FETCH NEXT FROM cur INTO field_value;
WHILE(done=FALSE) DO
UPDATE orderitems SET orderitems.item_price=field_value WHERE orderitems.f_id = (SELECT f_id FROM fruits WHERE f_price = field_value);
FETCH NEXT FROM cur INTO field_value;
END WHILE;
CLOSE cur;
END
运行结果:
原因分析:根据给定的代码,它只会将orderitems表中的每个item_price都改为相同的数值,这是因为在循环中,每次迭代都会使用从游标中获取的第一个f_price值来更新orderitems表。因此,无论游标中的其他f_price值是什么,它们都会被忽略,并且只有第一个f_price值会被用于更新操作。