實驗報告
課程名稱:數據庫原理及應用
實驗項目名稱:存儲過程、觸發器的創建和使用
實驗時間:2021 年 6 月 23 日
實驗目的
- 了解觸發器的概念
- 掌握創建觸發器的方法
- 掌握查看、刪除觸發器信息的方法
- 了解存儲過程的概念
- 掌握創建、執行存儲過程的方法
- 了解查看、修改和刪除存儲過程的方法
實驗環境
MySQL、SQLyog
實驗內容及過程
在課本 P79 頁的學生-課程數據庫基礎上,完成以下實驗內容
1.觸發器
- 定義 BEFORE 行級觸發器,為 Stduent 表定義完整性規則“學生的年齡的取值范圍為 14~50 的整數”,若年齡的值不在 14~50 之間,則拒絕修改或插入,並拋出提示信息,以便於操作者查找問題。(需定義兩個觸發器,分別為 insert 事件和 update 事件類型),需要設計測試例子驗證觸發器是否工作。
DELIMITER //
CREATE TRIGGER trig_insert_student
BEFORE INSERT ON student
FOR EACH ROW
BEGIN
DECLARE msg VARCHAR(200);
IF new.sage NOT BETWEEN 14 AND 50 THEN
SET msg = CONCAT('插入時出錯,您輸入的年齡:', new.sage, '為無效值,請輸入 14 到 50 以內的有效值。');
SIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT = msg;
END IF;
END//
DELIMITER ;
INSERT Student(Sno, Sname, Ssex, Sage, Sdept)
VALUES (201215129,'小明','男',13,'CS');
DROP TRIGGER IF EXISTS trig_update_student;
DELIMITER //
CREATE TRIGGER trig_update_student
BEFORE UPDATE ON student
FOR EACH ROW
BEGIN
DECLARE msg VARCHAR(200);
IF new.sage NOT BETWEEN 14 AND 50 THEN
SET msg = CONCAT('更新時出錯,您輸入的年齡:', new.sage, '為無效值,請輸入 14 到 50 以內的有效值。');
SIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT = msg;
END IF;
END//
DELIMITER ;
UPDATE student
SET Sage=13
WHERE Sno=201215121;
- 定義一個觸發器,當一個學生的選課記錄被刪除時,把該學生學號、課程號、成績添加到 deletesc 表中,需要設計測試例子驗證觸發器是否工作。
USE st;
CREATE TABLE DELETESC
(Sno CHAR(9),
Cno CHAR(4),
Grade SMALLINT
);
DROP TRIGGER IF EXISTS trig_del_student;
DELIMITER//
CREATE TRIGGER trig_del_student
AFTER DELETE ON SC
FOR EACH ROW
BEGIN
INSERT INTO DELETESC
VALUES(old.Sno,old.Cno,old.Grade);
END//
DELIMITER ;
DELETE FROM SC
WHERE Sc.Sno = '201215122';
SELECT *
FROM DELETESC;
- 限制數據結構課程最多 5 名學生選修,需要設計測試例子驗證觸發器是否工作。
DELIMITER //
CREATE TRIGGER trig_insert_sc
BEFORE INSERT ON SC
FOR EACH ROW
BEGIN
DECLARE num INT;
DECLARE msg VARCHAR(200);
DECLARE cname VARCHAR(200);
SET cname = '數據結構';
SELECT COUNT(*) INTO num FROM course, sc
WHERE course.cno = sc.cno AND course.cname = cname;
IF num >= 5 THEN
SET msg = CONCAT('當前',cname,'選修人數:', num,' 最大選修人數為 5' );
SIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT = msg;
END IF;
END//
DELIMITER ;
INSERT Student(Sno, Sname, Ssex, Sage, Sdept)
VALUES (201215124,'小明','男',20,'CS'),
(201215126,'小紅','男',19,'IS');
INSERT INTO sc VALUES('201215121', 5, 90);
INSERT INTO sc VALUES('201215122', 5, 90);
INSERT INTO sc VALUES('201215123', 5, 90);
INSERT INTO sc VALUES('201215124', 5, 90);
INSERT INTO sc VALUES('201215125', 5, 90);
- 查看 (1) 觸發器的創建信息
SHOW CREATE TRIGGER trig_insert_student;
- 刪除 (2) 所創建的觸發器
DROP TRIGGER IF EXISTS trig_del_student;
- (選做題)定義一個觸發器,當插入一條新生記錄時,關系 studentcount(dept CHAR(20), stucount SMALLINT)中對應系的學生總人數需跟着改變,若關系 studentcount 中對應系已存在,只需要更新總人數,若不存在,需插入系名及總人數。需要設計測試例子驗證觸發器是否工作。
USE st;
CREATE TABLE StudentCount
(dept CHAR(20),
stucount SMALLINT
);
DROP TRIGGER IF EXISTS trig_update_studentcount;
DELIMITER //
CREATE TRIGGER trig_update_studentcount
AFTER INSERT ON Student
FOR EACH ROW
BEGIN
DECLARE exist INT;
SET exist = EXISTS (SELECT * FROM studentcount WHERE StudentCount.dept=new.Sdept);
IF exist = 0 THEN
INSERT INTO StudentCount
SELECT Sdept,COUNT(Sno)
FROM student
WHERE student.Sdept=new.Sdept
GROUP BY Sdept;
ELSE
UPDATE studentcount
SET stucount=stucount+1
WHERE StudentCount.dept=new.Sdept;
END IF;
END//
DELIMITER ;
UPDATE studentcount
SET stucount=stucount+1
WHERE StudentCount.dept='IS';
SELECT EXISTS (SELECT * FROM studentcount WHERE StudentCount.dept='IS')
SELECT EXISTS (SELECT * FROM studentcount WHERE StudentCount.dept='de')
INSERT Student(Sno, Sname, Ssex, Sage, Sdept)
VALUES (201215127,'小張','男',20,'CS');
2.存儲過程
- 創建一個存儲過程,完成的功能是在表 student,course 和 sc 中查詢以下字段:學號、姓名、課程名稱、考試分數,需調用該存儲過程驗證結果。
USE st;
DELIMITER //
CREATE PROCEDURE get_basic_info()
BEGIN
SELECT Student.Sno,Student.Sname,Course.Cname,Sc.Grade
FROM Student,Course,Sc
WHERE Student.Sno=Sc.Sno AND Sc.Cno=Course.Cno;
END //
DELIMITER ;
CALL get_basic_info();
- 創建一個帶有參數的存儲過程,該存儲過程根據傳入的學生編號,在 student 表中查詢此學生的信息,需調用該存儲過程驗證結果。
DELIMITER //
CREATE PROCEDURE get_stu_by_sno(IN Sno CHAR(9))
BEGIN
SELECT *
FROM Student
WHERE Student.Sno=Sno;
END //
DELIMITER ;
CALL get_stu_by_sno('201215121');
- 創建存儲過程,根據指定的課程名(輸入參數)返回該課程的最高分、最低分、平均分(輸出參數)。要求在創建存儲過程前要先判斷該存儲過程是否已存在,如果存在,則將其刪除,需調用該存儲過程驗證結果。
DROP PROCEDURE IF EXISTS get_course_score;
DELIMITER //
CREATE PROCEDURE get_course_score(IN Cname CHAR(4),
OUT max_grade SMALLINT,
OUT min_grade SMALLINT,
OUT avg_grade SMALLINT)
BEGIN
SELECT MAX(Grade),MIN(Grade),AVG(Grade) INTO max_grade,min_grade,avg_grade
FROM SC,course
WHERE Course.Cname=Cname AND Course.Cno=SC.Cno;
END //
DELIMITER ;
SET @max_grade = 0,@min_grade=0,@avg_grade=0;
CALL get_course_score('數據結構',@max_grade,@min_grade,@avg_grade);
SELECT @max_grade,@min_grade,@avg_grade;
- 使用 SHOW CREATE 查看(1)中存儲過程信息,SHOW STATUS 查看 (2) 中存儲過程信息,從 information_schema.routine 表中查看 (3) 中存儲過程信息。
SHOW CREATE PROCEDURE get_basic_info;
SHOW PROCEDURE STATUS LIKE 'get_stu_by_sno';
USE information_schema;
SELECT *
FROM routines
WHERE routine_name = 'get_course_score';
- 修改 (1) 中的存儲過程定義,將讀寫權限改為 MODIFIES SQL DATA,並指明調用者可以執行,添加注釋信息。
ALTER PROCEDURE get_basic_info
MODIFIES SQL DATA
SQL SECURITY INVOKER;
- 刪除 (1) 中的存儲過程
DROP PROCEDURE IF EXISTS get_basic_info;
- (選做題)統計離散數學的成績分部情況,即按照分數段統計人數。
DROP PROCEDURE IF EXISTS get_course_score_status;
DELIMITER //
CREATE PROCEDURE get_course_score_status(IN Cno CHAR(4))
BEGIN
SELECT MAX(Grade),MIN(Grade),AVG(Grade) INTO max_grade,min_grade,avg_grade
FROM SC
WHERE SC.Cno=Cno;
END //
DELIMITER ;
- (選做題)統計任意一門課的平均成績
DROP PROCEDURE IF EXISTS get_course_avg_score;
DELIMITER //
CREATE PROCEDURE get_course_avg_score(IN Cno CHAR(4))
BEGIN
SELECT AVG(Grade) INTO max_grade,min_grade,avg_grade
FROM SC
WHERE SC.Cno=Cno;
END //
DELIMITER ;
- (選做題)將學生選課成績從百分制改為等級制(即 A B C D E)
ALTER TABLE SC
ADD Lev CHAR(4);
DELIMITER //
CREATE PROCEDURE SClev()
BEGIN
UPDATE SC SET Lev='A' WHERE Grade>=90 AND Grade <=100;
UPDATE SC SET Lev='B' WHERE Grade>=80 AND Grade<90;
UPDATE SC SET Lev='C' WHERE Grade>=70 AND Grade<80;
UPDATE SC SET Lev='D' WHERE Grade>=60 AND Grade<70;
UPDATE SC SET Lev='E' WHERE Grade<60;
END //
DELIMITER ;
EXEC SClev;
SELECT * FROM SC;
實驗心得
通過本次實驗,我了解觸發器的概念,掌握創建觸發器的方法,掌握查看、刪除觸發器信息的方法,了解存儲過程的概念,掌握創建、執行存儲過程的方法,同時了解查看、修改和刪除存儲過程的方法,收獲頗豐。