头歌实训之存储过程、函数与触发器

🌟 各位看官好,我是 maomi_9526

🌍 种一棵树最好是十年前,其次是现在!

🚀 今天来学习C语言的相关知识。

👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更多人哦

目录

第1关:创建存储过程

第2关:创建函数-count_credit

第3关:存储过程中使用游标

第4关:创建触发器-计算总学分

第5关:创建触发器-级联删除

总结:头歌第二关及第三关

问题分析:


第1关:创建存储过程

任务描述

本关任务:创建存储过程,实现对学生姓名进行模糊查询。

相关知识

为了完成本关任务,你需要掌握:

1.存储过程的定义;

2.存储过程的创建;

3.存储过程的执行。

存储过程的定义

存储过程(Stored Procedure)是数据库中一组预编译的SQL语句集合,存储在数据库中,可以被应用程序调用。存储过程可以包含复杂的逻辑、变量、条件判断和循环等,能够实现一些复杂的业务逻辑,提高代码的复用性和执行效率。

存储过程的创建

创建存储过程格式:

DELIMITER //

CREATE PROCEDURE 过程名([参数列表])

BEGIN

-- SQL语句

END //

DELIMITER ;

  • DELIMITER:MySQL 默认的语句分隔符是分号(;),但在存储过程中,分号可能会被用作语句的分隔符,因此需要使用 DELIMITER 关键字来改变分隔符,通常将其改为 // 或其他符号,以免与存储过程内部的分号冲突。
  • 存储过程名称:存储过程的名称,用于后续调用存储过程时标识该存储过程。
  • 参数列表:存储过程的参数,可以有输入参数(IN)、输出参数(OUT)和输入输出参数(INOUT)。参数的格式为 参数名 参数类型,例如 IN id INT 表示一个输入参数 id,类型为整数。
  • BEGIN...END:存储过程的主体部分,包含需要执行的 SQL 语句。

执行存储过程

  • 调用存储过程的语法如下:

CALL 存储过程名称(参数值);

  • 存储过程名称:要调用的存储过程的名称。
  • 参数值:调用存储过程时传递的参数值(实参),参数值的顺序和类型应与存储过程定义时的参数列表一致。

编程要求

根据提示,在右侧编辑器补充代码,创建存储过程pro_findname(IN word CHAR(1)) 对学生姓名进行模糊查找,输入任一汉字,输出姓名中含有该汉字的全部学生信息。

测试说明

平台会对你编写的代码进行测试,将调用你编写的存储过程:call pro_findname('明'),具体输出请参考右侧测试集。


开始你的任务吧,祝你成功!

复制代码
 use teachingdb;
 /****请在此编写代码,操作完毕之后点击评测******/
DELIMITER $$
 /**********Begin**********/
 
 create procedure pro_findname(in word char(10))
 Begin
    select * from student where sname like concat('%',word,'%');
End $$

 /**********End**********/
DELIMITER ;

第2关:创建函数-count_credit

任务描述

本关任务:创建和使用存储函数。

相关知识

为了完成本关任务,你需要掌握:

  • 创建存储函数;
  • 调用存储函数。

创建存储函数

  • 存储函数(Stored Function)是一种在数据库中存储的可调用的函数,类似于存储过程,但存储函数的主要目的是返回一个值,而存储过程主要用于执行一系列操作。存储函数可以被 SQL 语句直接调用,也可以在其他存储过程或存储函数中调用。
  • 创建存储函数格式

DELIMITER //

CREATE FUNCTION 函数名称 (参数列表)

RETURNS 返回值类型 READS SQL DATA

BEGIN

-- 函数的 SQL 语句

RETURN 返回值;

END//

DELIMITER ;

调用函数

  • SELECT 函数名称(参数值);
  • 在表达式中使用函数名称(参数值)。

编程要求

根据提示,在右侧编辑器补充代码,设计函数 count_credit(sno CHAR(6)),根据学号(sno)计算该学生的总学分,只有当成绩大于等于60分时才能获得该门课程的学分。

测试说明

平台会对你编写的代码进行测试:本题中该学生选"马蓉",学号为"97001")


开始你的任务吧,祝你成功!

复制代码
 use teachingdb;
 /****请在此编写代码,操作完毕之后点击评测******/
 
 /**********Begin**********/
  delimiter ##
  create Function count_credit(v_sno char(6))
  returns int reads sql data
  Begin
  declare sums int ;
  select sum(credit) into sums from course natural join score where grade >=60 and v_sno=sno;
    return sums;
  end ##
  delimiter ;
  
 /**********End**********/

第3关:存储过程中使用游标

任务描述

本关任务:创建存储过程 ,在存储过程中定义游标计算总学分。

相关知识

为了完成本关任务,你需要掌握:

1.游标的定义;

2.游标的使用。

游标的定义

游标(Cursor)主要用于存储过程和函数中,用于逐行处理查询结果集。

  • 在存储过程或函数中,使用 DECLARE CURSOR 语句来创建游标。

DECLARE cursor_name CURSOR FOR select_statement;

游标的使用

  • 打开游标

OPEN cursor_name;

  • 获取数据

FETCH cursor_name INTO var_name1, var_name2, ...;

  • 关闭游标

CLOSE cursor_name;

举例:通过游标获取users表中的id,name,并输出结果。

DELIMITER //

CREATE PROCEDURE process_users()

BEGIN

-- 声明变量

DECLARE finished INTEGER DEFAULT 0;

DECLARE user_id INT DEFAULT 0;

DECLARE user_name VARCHAR(50) DEFAULT '';

-- 声明游标

DECLARE my_cursor CURSOR FOR SELECT id, name FROM users;

-- 声明结束处理

DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;

-- 打开游标

OPEN my_cursor;

-- 获取数据

fetch_loop: LOOP

FETCH my_cursor INTO user_id, user_name;

IF finished = 1 THEN

LEAVE fetch_loop;

END IF;

-- 处理每一行数据

SELECT user_id, user_name;

END LOOP;

-- 关闭游标

CLOSE my_cursor;

END //

DELIMITER ;

编程要求

根据提示,在右侧编辑器补充代码,创建存储过程 p_count_credit,在存储过程中创建游标stucur保存所有学生的学号,使用loop循环从游标中提取每个学生的学号,根据当前学号调用count_credit 函数计算学生的总学分,并更新学生表中的总学分值。

测试说明

平台会对你编写的代码进行测试,将调用你编写的存储过程p_count_credit,函数的count_credit的功能和第2关中的相同,具体输出请参考右侧测试集。


开始你的任务吧,祝你成功!

复制代码
 use teachingdb;
 /****请在此编写代码,操作完毕之后点击评测******/
 
 /**********Begin**********/

 drop procedure if exists p_count_credit;
 delimiter ##
  create procedure  p_count_credit()
  begin
    declare v_sno varchar(20);
    declare v_credit int default 0;
    declare stucur cursor for select sno from student;
    declare exit handler for not found close stucur ;
    open stucur;
    while true do
    fetch stucur into v_sno;
    update student set totalcredit =count_credit(v_sno) where sno=v_sno;
    end while;
    close stucur;
    select *from student;
    end ##
  delimiter ;
 /**********End**********/

第4关:创建触发器-计算总学分

任务描述

本关任务:创建触发器 sum_credit,实现对 student 表总学分的计算。

相关知识

为了完成本关任务,你需要掌握:

1.触发器的定义;

2.触发器的创建。

触发器的定义

触发器(Trigger)是一种特殊的存储过程,它在表上的数据发生变化(如INSERT、UPDATE 和 DELETE操作)时自动执行。触发器的主要作用是维护数据的完整性和一致性,或者在数据变化时执行一些自动化的操作。

  • 触发时机:触发器可以设置在数据操作之前(BEFORE)或之后(AFTER)执行。
  • 触发事件:可以是INSERT、UPDATE或DELETE操作。

创建触发器的语法:

CREATE TRIGGER trigger_name

{BEFORE | AFTER} {INSERT | UPDATE | DELETE} ON table_name

FOR EACH ROW

BEGIN

-- 触发器要执行的SQL语句

END;

  • BEFORE 或 AFTER 指定触发器应在事件之前还是之后触发。
  • INSERT, UPDATE, 或 DELETE 指定触发器应该响应的事件类型。

触发器表

  • 在 MySQL 触发器中,NEW 和 OLD 是两个特殊的虚拟表(实际上它们是行数据的引用),用于访问触发事件中涉及的数据。这两个虚拟表的具体含义和用途取决于触发器所关联的操作类型(INSERT、UPDATE 或 DELETE)。
  • NEW 表
    • NEW 表表示即将插入到表中的新行数据,或者在更新操作中表示更新后的新值。
    • 可用场景: 在 BEFORE INSERT 和 AFTER INSERT 中,NEW 表示将要插入的新行。 在 BEFORE UPDATE 和 AFTER UPDATE 中,NEW 表示更新后的字段值。
    • 用法:可以通过 NEW.column_name 来访问或修改某一列的值。

示例

(1)创建一触发器 t_u_s,实现在更新学生表的学号时,同时更新 grade 表中的相关记录的 student 的 id 值。

CREATE TRIGGER t_u_s

AFTER UPDATE ON student

for EACH ROW

BEGIN

UPDATE grade SET studentid = new.studentid WHERE studentid = old.studentid;

END

  • OLD 表
  • OLD 表表示被删除或更新的旧行数据。
  • 可用场景: 在 BEFORE DELETE 和 AFTER DELETE 中,OLD 表示将要被删除的行。 在 BEFORE UPDATE 和 AFTER UPDATE 中,OLD 表示更新前的字段值。
  • 用法:可以通过 OLD.column_name 来访问某一列的值,但不能对其进行修改(因为它是只读的)。

示例

(2)建一个触发器 t_d_s,当删除表 student 中某个学生的信息时,同时将 grade 表中与该学生有关的数据全部删除。

CREATE TRIGGER trigger_t1

AFTER DELETE ON student

FOR EACH ROW

BEGIN

DELETE FROM grade WHERE studentid = old.studentid;

END

编程要求

根据提示,在右侧编辑器补充代码,创建触发器 sum_credit,实现对 student 表总学分的计算,当 score 中添加一条记录时,student 表总学分的值做相应改变。当课程成绩大于等于60分时,将该课程的学分加到该学生的总学分中。

测试说明

平台会对你编写的代码进行测试:平台会用"马小燕"为测试用例进行测试。


开始你的任务吧,祝你成功!

复制代码
 use teachingdb;
 /****请在此编写代码,操作完毕之后点击评测******/
 
 /**********Begin**********/
 delimiter ##
  create trigger sum_credit
  after insert on score for each row
  Begin
  if(new.grade>=60) then
        update student set totalcredit =totalcredit+(select credit from course where cno=new.cno)
        where student.sno=new.sno;
    end if;
    end ##
    delimiter ;

  
 /**********End**********/

第5关:创建触发器-级联删除

任务描述

本关任务:创建级联删除触发器 。

相关知识

为了完成本关任务,你需要掌握:

1.级联删除的定义;

2.级联删除的工作原理。

级联删除的定义

  • 级联删除(Cascade Delete)是数据库管理系统中的一种功能,用于定义外键约束时指定的删除规则。当一个表中的记录被删除时,所有关联的记录也会根据级联删除规则自动删除。这确保了数据的一致性,避免出现孤立记录(即那些指向已删除记录的外键值)。

级联删除的工作原理

  • 级联删除的工作原理
    • 假设你有两个表:Parent 和 Child。Child 表通过外键关联到 Parent 表。当你在 Parent 表上设置级联删除时,如果从 Parent 表中删除一条记录,那么所有在 Child 表中与这条记录相关联的记录也将被自动删除。

编程要求

根据提示,在右侧编辑器补充代码,创建级联删除触发器 del_student_score,当删除 student 表中的某学生时,也删除 score 表中的对应学号的学生选课记录。

测试说明

平台会对你编写的代码进行测试。


开始你的任务吧,祝你成功!

复制代码
 use teachingdb;
 /****请在此编写代码,操作完毕之后点击评测******/
 
 /**********Begin**********/
  delimiter ##
  create trigger del_studnet_score
  before delete on student for each row
  begin
    delete from score where sno=old.sno;
    end ##
  delimiter ;
 /**********End**********/

总结:头歌第二关及第三关

常见答题系统工作原理:

问题分析:

在头歌平台的测试过程中,由于他们只进行公开测试用例的验证,部分潜在的逻辑错误可能没有被及时发现。这种情况尤其会影响到 MySQL 相关的习题,因为这些习题通常会涉及到数据库操作的细节,如果没有合适的隐藏测试用例,某些问题可能不会暴露。

例如实验五第二关:

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 自己代码: | 官方代码: |
| use teachingdb; /****请在此编写代码,操作完毕之后点击评测******/ /**********Begin**********/ delimiter ## create Function count_credit(v_sno char(6)) returnsfloat reads sql data Begin declare sumsfloat****; select sum(credit) into sums from course natural join score where grade >=60 and v_sno=sno; return sums; end ## delimiter ; /**********End**********/ | CREATE DEFINER=`root`@`localhost` FUNCTION `count_credit`(stuno CHAR(6)) RETURNS int(11) READS SQL DATA BEGIN DECLARE stucno CHAR(3); DECLARE cred INT DEFAULT 0; DECLARE t_credINT DEFAULT 0; DECLARE done INT DEFAULT FALSE; -- 定义游标,从score表中获取学生所选课程编号 DECLARE stucur CURSOR FOR SELECT cno FROM score WHERE sno = stuno AND grade >= 60; -- 定义处理游标未找到数据时的行为 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; -- 打开游标 OPEN stucur; -- 循环获取课程编号并累加学分 loop_cursor: LOOP FETCH stucur INTO stucno; IF done THEN LEAVE loop_cursor; END IF; -- 获取课程学分 SELECT credit INTO cred FROM course WHERE cno = stucno; -- 累加学分 SET t_cred = t_cred + cred; END LOOP; -- 返回总学分 RETURN t_cred; END |

勘误:因为官方只进行公开实例进行测试,这里都可以进行通过

Mysql习题一般都是继续使用官方的代码进行测试,如果你在第三关依旧写出float的代码 */

复制代码
 use teachingdb;
 /****请在此编写代码,操作完毕之后点击评测******/
 
 /**********Begin**********/
select sum(credit) from score natural join course  where sno='96002';
 drop procedure if exists p_count_credit;
 delimiter ##
  create procedure  p_count_credit()
  begin
    declare v_sno varchar(20);
    declare v_credit float default 0;
    declare stucur cursor for select sno from student;
    declare exit handler for not found close stucur ;
    open stucur;
    while true do
    fetch stucur into v_sno;
    select sum(credit) into v_credit from score natural join course where grade>=60 and sno=v_sno;
    update student set totalcredit =ifnull(v_credit,0) where sno=v_sno;
    end while;
    close stucur;
    select *from student;
    end ##
  delimiter ;
 /**********End**********/

由于头歌平台的测试机制仅依赖于公开的测试用例,这导致了部分潜在的逻辑问题没有被及时发现。尽管我们无法修改平台的测试方式或其隐藏的测试用例,但我们可以选择按照平台提供的标准函数进行测试,以确保代码在实际评测时能够正确运行。

本次纠错并没有涉及复杂的新知识点,而是希望同学们能够理解,为什么在这种情况下,某些潜在的错误未被立即发现,当大家出现这种情况也可以通过下面这种方法来通过测试:

相关推荐
松树戈1 小时前
PostgreSQL使用LIKE右模糊没有走索引分析&验证
数据库·postgresql
文牧之1 小时前
PostgreSQL 常用日志
运维·数据库·postgresql
TE-茶叶蛋1 小时前
Redis 原子操作
数据库·redis·缓存
Linux运维老纪1 小时前
Python文件操作及数据库交互(Python File Manipulation and Database Interaction)
linux·服务器·数据库·python·云计算·运维开发
Bruce_Liuxiaowei1 小时前
MCP Python SDK构建的**SQLite浏览器**的完整操作指南
数据库·python·sqlite
数据与人工智能律师2 小时前
正确应对监管部门的数据安全审查
大数据·网络·数据库·人工智能·区块链
2401_897930062 小时前
什么是非关系型数据库
数据库·oracle
鱼丸丶粗面2 小时前
Python 读取 txt 文件详解 with ... open()
linux·数据库·python
拾荒者.1262 小时前
设计一个关键字统计程序:利用HashMap存储关键字统计信息,对用户输入的关键字进行个数统计。
数据库·python·mysql
encoding-console2 小时前
欧拉环境(openEuler 22.03 LTS SP3)安装移动磐维数据库(PanWeiDB_V2.0-S2.0.2_B01)步骤
数据库·虚拟机·欧拉·磐维数据库