目录
一、实验目的与要求:
二、实验内容:
三、实验小结
实验中涉及到的数据及内容:数据库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
    );
END2测试函数
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;
END2测试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;
END2测试代码
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;
END2测试代码:
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值会被用于更新操作。



















