Lab5 实验报告

Task1

1.1

DELIMITER //  
CREATE PROCEDURE password_check_or_change(  
    IN in_username varchar(20),  
    IN in_password varchar(20),  
    IN in_new_password varchar(20),  
    IN in_action int,  
    OUT result int  
)  
BEGIN  
    declare temp_pwd varchar(20);  
    declare temp_uname varchar(20);  
    declare done int default 0;  
    declare cur cursor for select user_name, password from account;  
    declare continue handler for not found set done = true;  
    set result = false;  
  
    open cur;  
    read_loop: LOOP  
        fetch cur into temp_uname, temp_pwd;  
        if done then  
            leave read_loop;  
        end if;  
        if in_action = 1 then  
            if temp_uname = in_username and temp_pwd = in_password then  
                set result = true;  
            end if;  
        end if;  
        if in_action = 2 then  
            if temp_uname = in_username and temp_pwd = in_password and  
               in_new_password regexp '^[A-Za-z0-9]{4,10}$' then  
                    update account set password = in_new_password  
                       where user_name = in_username and password = in_password;  
                    set result = true;  
            end if;  
        end if;  
    end loop;  
    close cur;  
end//  
delimiter ;  
  
-- 测试1:检查正确密码(返回 1)  
CALL password_check_or_change('aaa', '1234', NULL, 1, @result);  
SELECT @result;  
  
-- 测试2:修改密码为非法格式(返回 0)  
CALL password_check_or_change('aaa', '1234', 'ab#', 2, @result);  
SELECT @result;  
  
-- 测试3:修改密码为合法格式(返回 1)  
CALL password_check_or_change('aaa', '1234', 'newPass123', 2, @result);  
SELECT @result;

Pasted image 20250425170811.png
Pasted image 20250425170957.png
Pasted image 20250425171010.png
Pasted image 20250425171018.png
Pasted image 20250425171034.png

1.2

DELIMITER //  
CREATE PROCEDURE borrow_book(  
    IN in_username varchar(20),  
    IN in_ISBN varchar(20),  
    OUT result int  
)  
BEGIN  
    declare temp_uid int;  
    declare temp_num int;  
    declare temp_borrowed int;  
    set result = false;  
  
    select user_id into temp_uid from account where user_name = in_username;  
    select num into temp_num from library where ISBN = in_ISBN;  
    select count(*) into temp_borrowed from record  
    where user_name = in_username and ISBN = in_ISBN and return_time is NULL;  
    if temp_uid IS NOT NULL and temp_num >= 1 and temp_borrowed = 0 then  
        update library set num = num-1 where ISBN = in_ISBN;  
        insert into record(user_id, user_name, ISBN, borrow_time, expire_time, return_time) values (temp_uid, in_username, in_ISBN, CURDATE(), CURDATE() + INTERVAL 30 DAY, NULL);  
        set result = true;  
    end if;  
end//  
delimiter ;  
  
-- 测试1:用户不存在(返回 0)  
CALL borrow_book('bbb', '9781234567890', @result);  
SELECT @result;  
  
-- 测试2:库存不足(返回 0)  
UPDATE library SET num = 0 WHERE ISBN = '9781234567890';  
CALL borrow_book('aaa', '9781234567890', @result);  
SELECT @result;  
  
-- 测试3:成功借书(返回 1)  
UPDATE library SET num = 5 WHERE ISBN = '9781234567890';  
CALL borrow_book('aaa', '9781234567890', @result);  
SELECT @result;

Pasted image 20250425200144.png
Pasted image 20250425200153.png
Pasted image 20250425200207.png
Pasted image 20250425200221.png
Pasted image 20250425200229.png

1.3

DELIMITER //  
CREATE PROCEDURE return_book(  
    IN in_username varchar(20),  
    IN in_ISBN varchar(20),  
    OUT result int  
)  
BEGIN  
    declare temp_uid int;  
    declare temp_borrowed int;  
    set result = false;  
  
    select user_id into temp_uid from account where user_name = in_username;  
    select count(*) into temp_borrowed from record  
    where user_name = in_username and ISBN = in_ISBN and return_time is NULL;  
    if temp_uid IS NOT NULL and temp_borrowed = 1 then  
        update library set library.num = library.num + 1 where library.ISBN = in_ISBN;  
        update record set record.return_time = CURDATE()  
                      where record.user_name = in_username and record.ISBN = in_ISBN and record.return_time IS NULL;  
        set result = true;  
    end if;  
end//  
delimiter ;  
  
-- 测试1:无借阅记录(返回 0)  
CALL return_book('aaa', 'invalid_isbn', @result);  
SELECT @result;  
  
-- 测试2:成功还书(返回 1)  
CALL return_book('aaa', '9781234567890', @result);  
SELECT @result;  
  
-- 测试3:重复还书(返回 0)  
CALL return_book('aaa', '9781234567890', @result);  
SELECT @result;

Pasted image 20250425203122.png
Pasted image 20250425203127.png
Pasted image 20250425203135.png
Pasted image 20250425203148.png
Pasted image 20250425203156.png

1.4

delimiter //  
create procedure view_records(in in_username varchar(50))  
begin  
    declare temp_ISBN varchar(13);  
    declare temp_exdate date;  
    declare done int default 0;  
    -- 声明游标遍历未归还记录  
    declare cur cursor for  
        select ISBN, expire_time from record  
        where user_name = in_username and return_time is NULL;  
    declare continue handler for not found set done = 1;  
  
    -- 创建临时结果表  
    create temporary table if not exists temp_results (ISBN varchar(20), expire_time date);  
  
    open cur;  
    read_loop: loop  
        fetch cur into temp_ISBN, temp_exdate;  
        if done then  
            leave read_loop;  
        end if;  
        insert into temp_results values(temp_ISBN, temp_exdate);  
    end loop;  
    close cur;  
  
    select in_username as username, ISBN, expire_time from temp_results;  
    drop temporary table temp_results;  
end //  
delimiter ;  
  
-- 测试1:无借阅记录(返回空)  
CALL view_records('bbb');  
  
-- 测试2:存在未归还记录(返回记录)  
CALL borrow_book('bbb', '9781234567890', @result);  
CALL view_records('bbb');  
  
-- 测试3:已归还记录不显示  
CALL return_book('bbb', '9781234567890', @result);  
CALL view_records('bbb');

Pasted image 20250425205958.png
Pasted image 20250425205951.png
Pasted image 20250425210008.png

2

// 插入
DELIMITER //
CREATE TRIGGER after_sells_insert
AFTER INSERT ON sells
FOR EACH ROW
BEGIN
    -- 计算总金额并更新客户等级
    UPDATE customer c
    SET c.level = (
        SELECT CASE 
            WHEN SUM(f.price * s.quantity) >= 20000 THEN 'SVIP'
            WHEN SUM(f.price * s.quantity) >= 10000 THEN 'VIP'
            ELSE 'normal'
        END
        FROM sells s
        JOIN fruits f ON s.fid = f.fid
        WHERE s.cid = NEW.cid
    )
    WHERE c.cid = NEW.cid;
END //
DELIMITER ;

// 更新
DELIMITER //
CREATE TRIGGER after_sells_update
AFTER UPDATE ON sells
FOR EACH ROW
BEGIN
    -- 处理旧客户
    UPDATE customer c
    SET c.level = (
        SELECT CASE 
            WHEN SUM(f.price * s.quantity) >= 20000 THEN 'SVIP'
            WHEN SUM(f.price * s.quantity) >= 10000 THEN 'VIP'
            ELSE 'normal'
        END
        FROM sells s
        JOIN fruits f ON s.fid = f.fid
        WHERE s.cid = OLD.cid
    )
    WHERE c.cid = OLD.cid;

    -- 处理新客户(如果 cid 被修改)
    IF NEW.cid != OLD.cid THEN
        UPDATE customer c
        SET c.level = (
            SELECT CASE 
                WHEN SUM(f.price * s.quantity) >= 20000 THEN 'SVIP'
                WHEN SUM(f.price * s.quantity) >= 10000 THEN 'VIP'
                ELSE 'normal'
            END
            FROM sells s
            JOIN fruits f ON s.fid = f.fid
            WHERE s.cid = NEW.cid
        )
        WHERE c.cid = NEW.cid;
    END IF;
END //
DELIMITER ;

// 删除
DELIMITER //
CREATE TRIGGER after_sells_delete
AFTER DELETE ON sells
FOR EACH ROW
BEGIN
    -- 更新旧客户的等级
    UPDATE customer c
    SET c.level = (
        SELECT CASE 
            WHEN SUM(f.price * s.quantity) >= 20000 THEN 'SVIP'
            WHEN SUM(f.price * s.quantity) >= 10000 THEN 'VIP'
            ELSE 'normal'
        END
        FROM sells s
        JOIN fruits f ON s.fid = f.fid
        WHERE s.cid = OLD.cid
    )
    WHERE c.cid = OLD.cid;
END //
DELIMITER ;

// 验证
DELIMITER //
CREATE PROCEDURE test_triggers()
BEGIN
    -- 重置测试数据
    DELETE FROM sells;
    UPDATE customer SET level = 'normal' WHERE cid IN (1, 2);

    -- 测试1: 插入记录使总金额达到 VIP
    INSERT INTO sells (fid, cid, quantity) VALUES (1, 1, 2000); -- 5*2000 = 10000
    SELECT 'Test1 - After Insert VIP' AS Description, cid, level FROM customer WHERE cid = 1;

    -- 测试2: 插入记录使总金额达到 SVIP
    INSERT INTO sells (fid, cid, quantity) VALUES (1, 1, 2000); -- 5*4000 = 20000
    SELECT 'Test2 - After Insert SVIP' AS Description, cid, level FROM customer WHERE cid = 1;

    -- 测试3: 删除记录降级到 VIP
    DELETE FROM sells WHERE cid = 1 AND fid = 1 LIMIT 1;
    SELECT 'Test3 - After Delete VIP' AS Description, cid, level FROM customer WHERE cid = 1;

    -- 测试4: 修改记录升级到 SVIP
    UPDATE sells SET quantity = 3000 WHERE cid = 1 AND fid = 1; -- 5*3000 = 15000 → VIP
    SELECT 'Test4 - After Update VIP' AS Description, cid, level FROM customer WHERE cid = 1;

    -- 测试5: 修改客户 cid 触发跨客户更新
    UPDATE sells SET cid = 2 WHERE cid = 1; -- John 降级为 normal,Alice 升级为 VIP
    SELECT 'Test5 - After Update CID (John)' AS Description, cid, level FROM customer WHERE cid = 1;
    SELECT 'Test5 - After Update CID (Alice)' AS Description, cid, level FROM customer WHERE cid = 2;
END //
DELIMITER ;
-- 调用存储过程
CALL test_triggers();

Pasted image 20250425211134.png
Pasted image 20250425211147.png
Pasted image 20250425211152.png
Pasted image 20250425211158.png
Pasted image 20250425211205.png
Pasted image 20250425211211.png

Built with MDFriday ❤️