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

🌟 各位看官好,我是 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**********/

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

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

相关推荐
旋风菠萝13 分钟前
项目复习(1)
java·数据库·八股·八股文·复习·项目、
w236173460115 分钟前
Django框架漏洞深度剖析:从漏洞原理到企业级防御实战指南——为什么你的Django项目总被黑客盯上?
数据库·django·sqlite
2302_8097983242 分钟前
【JavaWeb】MySQL
数据库·mysql
drowingcoder1 小时前
MySQL相关
数据库
Musennn2 小时前
MySQL刷题相关简单语法集合
数据库·mysql
Think Spatial 空间思维3 小时前
【HTTPS基础概念与原理】TLS握手过程详解
数据库·网络协议·https
laowangpython3 小时前
MySQL基础面试通关秘籍(附高频考点解析)
数据库·mysql·其他·面试
mooyuan天天3 小时前
SQL注入报错“Illegal mix of collations for operation ‘UNION‘”解决办法
数据库·web安全·sql注入·dvwa靶场·sql报错
运维-大白同学3 小时前
go-数据库基本操作
开发语言·数据库·golang
R-sz4 小时前
通过从数据库加载MinIO配置并初始化MinioClient,spring boot之Minio上传
数据库·oracle