據(jù)庫課設(shè)實(shí)戰(zhàn):高校學(xué)籍管理系統(tǒng)SQL修正與觸發(fā)器實(shí)現(xiàn))
簡介這份數(shù)據(jù)庫原理課程設(shè)計(jì)報(bào)告以某高校學(xué)籍管理系統(tǒng)為完整案例面向計(jì)算機(jī)相關(guān)專業(yè)學(xué)生及數(shù)據(jù)庫初學(xué)者幫助讀者掌握從需求分析到物理設(shè)計(jì)的全流程實(shí)踐方法。報(bào)告圍繞學(xué)生信息、班級(jí)、課程、成績與獎(jiǎng)懲五大管理模塊展開涵蓋概念結(jié)構(gòu)、邏輯結(jié)構(gòu)與物理結(jié)構(gòu)設(shè)計(jì)并給出學(xué)生表、班級(jí)表、課程表、成績表、用戶表及獎(jiǎng)懲表的主外鍵定義與參照完整性約束方案。資源包內(nèi)含1個(gè)doc文檔壓縮后約440KB結(jié)構(gòu)緊湊便于直接查閱與二次修改。其中還涉及視圖創(chuàng)建、存儲(chǔ)過程統(tǒng)計(jì)各院系專業(yè)男女人數(shù)、觸發(fā)器自動(dòng)更新班級(jí)人數(shù)、check約束限制性別輸入等具體實(shí)現(xiàn)并附有主要功能程序段與模塊流程圖。目前已有1094人學(xué)習(xí)下載適合用作課程設(shè)計(jì)參考、實(shí)驗(yàn)報(bào)告模板或數(shù)據(jù)庫綜合練習(xí)的對(duì)照材料。1. 一份能跑通的學(xué)籍管理系統(tǒng)課設(shè)報(bào)告到底長什么樣如果你正在搜「數(shù)據(jù)庫原理課程設(shè)計(jì)報(bào)告 某高校的學(xué)籍管理系統(tǒng)」大概率是三種處境之一課設(shè) deadline 逼近手里只有題目沒有可參考的完整實(shí)現(xiàn)想照著別人的報(bào)告復(fù)現(xiàn)一遍結(jié)果發(fā)現(xiàn) SQL 語句全是語法錯(cuò)誤或者你已經(jīng)寫完了但觸發(fā)器、存儲(chǔ)過程、參照完整性這幾塊心里沒底想找個(gè)能對(duì)標(biāo)的版本核一遍。這份資源就是一份完整的數(shù)據(jù)庫原理課程設(shè)計(jì)報(bào)告主題是高校學(xué)籍管理系統(tǒng)覆蓋學(xué)生信息、班級(jí)、課程、成績、獎(jiǎng)懲五個(gè)業(yè)務(wù)模塊技術(shù)棧是 SQL 數(shù)據(jù)庫報(bào)告里寫的是 SQL 軟件 Windows XP 環(huán)境核心交付物包括建庫建表語句、視圖定義、觸發(fā)器、存儲(chǔ)過程、CHECK 約束以及參照完整性設(shè)計(jì)。它適合數(shù)據(jù)庫課程的本科生做課設(shè)參考也適合剛接觸 SQL 的開發(fā)者拿來當(dāng)?shù)谝粋€(gè)「從需求到建表到寫觸發(fā)器」的練手項(xiàng)目。需要先說明一點(diǎn)報(bào)告原文里的 SQL 語句存在不少拼寫和語法問題比如Create datebase、Creat table、PBIMARY、字段類型寫成Date(8)這種不存在的寫法。所以這份資源的價(jià)值不在于「復(fù)制粘貼就能跑」而在于它給出了一套完整的數(shù)據(jù)庫設(shè)計(jì)思路和模塊劃分你需要在此基礎(chǔ)上把 SQL 修正到能執(zhí)行的狀態(tài)。下面我會(huì)按「設(shè)計(jì)邏輯 → 建表實(shí)操 → 視圖/觸發(fā)器/存儲(chǔ)過程 → 避坑 → 進(jìn)階驗(yàn)證」的順序拆一遍讓你拿到手就能改、改完就能跑。2. 從需求到關(guān)系模式學(xué)籍管理系統(tǒng)的表結(jié)構(gòu)怎么定2.1 五個(gè)核心實(shí)體和它們的關(guān)系報(bào)告里把系統(tǒng)拆成了學(xué)生、班級(jí)、課程、成績、獎(jiǎng)懲、用戶六個(gè)實(shí)體其中用戶表是給登錄模塊用的跟業(yè)務(wù)數(shù)據(jù)關(guān)系不大。真正需要理清關(guān)系的是前五個(gè)。學(xué)生和班級(jí)是多對(duì)一一個(gè)學(xué)生屬于一個(gè)班級(jí)一個(gè)班級(jí)有多個(gè)學(xué)生。學(xué)生和課程是多對(duì)多中間通過成績表來關(guān)聯(lián)——成績表里同時(shí)出現(xiàn)學(xué)號(hào)和課程名這就是典型的關(guān)聯(lián)表設(shè)計(jì)。獎(jiǎng)懲表跟學(xué)生是一對(duì)多一個(gè)學(xué)生可以有多條獎(jiǎng)懲記錄。課程和班級(jí)之間報(bào)告里課程表有classname字段暗示課程是跟班級(jí)綁定的這個(gè)設(shè)計(jì)在實(shí)際選課場景下會(huì)有問題后面避坑章節(jié)會(huì)展開說。邏輯結(jié)構(gòu)設(shè)計(jì)里報(bào)告給出了關(guān)系模式學(xué)生姓名性別學(xué)號(hào)班級(jí)號(hào)專業(yè)出生日期入學(xué)日期家庭住址備注學(xué)號(hào)為主鍵班級(jí)班級(jí)號(hào)年級(jí)輔導(dǎo)員自習(xí)室班級(jí)號(hào)為主鍵課程課程名課程編號(hào)課程類型課程描述課程編號(hào)為主鍵成績學(xué)生姓名學(xué)號(hào)班級(jí)名稱課程名分?jǐn)?shù)學(xué)號(hào)課程名聯(lián)合主鍵獎(jiǎng)懲姓名學(xué)號(hào)年級(jí)輔導(dǎo)員學(xué)號(hào)為主鍵用戶用戶名密碼權(quán)限用戶名為主鍵這里有個(gè)細(xì)節(jié)值得注意成績表用「學(xué)號(hào)課程名」做聯(lián)合主鍵而不是用課程編號(hào)。用課程名做外鍵的問題是課程名可能重復(fù)或修改參照完整性會(huì)很脆弱。常見做法是成績表里存學(xué)號(hào)和課程編號(hào)通過課程編號(hào)關(guān)聯(lián)課程表。但報(bào)告原文用的是課程名你在復(fù)現(xiàn)時(shí)可以根據(jù)自己的需求決定是否改成課程編號(hào)。2.2 物理設(shè)計(jì)里的字段類型選擇報(bào)告給出了六張表的詳細(xì)字段定義我整理成一張對(duì)照表方便你直接照著建表表名字段報(bào)告中的類型建議修正類型說明studentsnoChar(15)CHAR(15)學(xué)號(hào)主鍵studentsnameChar(8)VARCHAR(20)姓名studentssexChar(2)CHAR(2)性別加 CHECK 約束studentscardChar(20)CHAR(18)身份證號(hào)studentsaddreeDate(8)DATE出生日期原文類型有誤studentsspecialityChar(20)VARCHAR(30)專業(yè)studentclassnameChar(10)VARCHAR(20)班級(jí)studentstelphoneChar(15)VARCHAR(15)聯(lián)系電話studentsmemoChar(50)VARCHAR(100)備注classclassnameChar(10)VARCHAR(20)班級(jí)名主鍵classtdepartmentChar(20)VARCHAR(30)所屬院系classtnameChar(8)VARCHAR(20)輔導(dǎo)員classclassroomChar(15)VARCHAR(20)教室classnumberChar(3)INT人數(shù)觸發(fā)器要加減必須用數(shù)值類型coursecidChar(10)CHAR(10)課程編號(hào)主鍵coursecoursenameChar(20)VARCHAR(30)課程名courseclassnameChar(20)VARCHAR(20)所屬班級(jí)courseperiodInt(4)INT學(xué)時(shí)coursetidChar(20)CHAR(10)教師編號(hào)scoresnoChar(15)CHAR(15)學(xué)號(hào)聯(lián)合主鍵scorecoursenameChar(10)VARCHAR(30)課程名聯(lián)合主鍵scorescoreInt(4)INT分?jǐn)?shù)jcsnameChar(20)VARCHAR(20)姓名主鍵jcgradeChar(20)VARCHAR(20)年級(jí)jcjdateDate(8)DATE獎(jiǎng)懲日期jcjnameChar(20)VARCHAR(30)獎(jiǎng)懲名稱jcjmemoChar(20)VARCHAR(100)備注這張表里最關(guān)鍵的修正有兩處一是class.number必須從Char(3)改成INT因?yàn)橛|發(fā)器里要對(duì)它做加減運(yùn)算字符類型做減法會(huì)直接報(bào)錯(cuò)二是所有Date(8)都要改成DATE標(biāo)準(zhǔn) SQL 里沒有帶精度的日期類型。這兩處不改后面的觸發(fā)器和存儲(chǔ)過程一定跑不起來。提示如果你用的是 MySQLCHAR和VARCHAR的區(qū)別在于 CHAR 是定長、VARCHAR 是變長。學(xué)號(hào)、身份證號(hào)這種長度固定的用 CHAR姓名、備注這種長度不固定的用 VARCHAR能省存儲(chǔ)空間。3. 建庫建表實(shí)操把報(bào)告里的 SQL 修到能執(zhí)行3.1 建庫和建表語句的修正版報(bào)告原文的建庫語句是Create datebase student;這里datebase拼錯(cuò)了正確寫法是DATABASE。建表語句里Creat table少了Eprimary key寫成了primary keys字段之間缺少逗號(hào)分隔。下面是我修正后的完整建表腳本以 MySQL 語法為準(zhǔn)SQL Server 用戶把AUTO_INCREMENT去掉即可-- 建庫 CREATE DATABASE student_db DEFAULT CHARACTER SET utf8mb4; USE student_db; -- 學(xué)生信息表 CREATE TABLE student ( sno CHAR(15) NOT NULL, sname VARCHAR(20) NOT NULL, ssex CHAR(2) NOT NULL, scard CHAR(18), sbirthday DATE, sspeciality VARCHAR(30), classname VARCHAR(20), stelphone VARCHAR(15), saddress VARCHAR(100), smemo VARCHAR(100), PRIMARY KEY (sno), CONSTRAINT chk_sex CHECK (ssex IN (男, 女)) ); -- 班級(jí)信息表 CREATE TABLE class ( classname VARCHAR(20) NOT NULL, tdepartment VARCHAR(30), tname VARCHAR(20), classroom VARCHAR(20), number INT DEFAULT 0, PRIMARY KEY (classname) ); -- 課程信息表 CREATE TABLE course ( cid CHAR(10) NOT NULL, coursename VARCHAR(30) NOT NULL, classname VARCHAR(20), termname VARCHAR(20), period INT, tid CHAR(10), classroomname VARCHAR(20), coursememo VARCHAR(100), PRIMARY KEY (cid) ); -- 成績信息表 CREATE TABLE score ( sno CHAR(15) NOT NULL, coursename VARCHAR(30) NOT NULL, sname VARCHAR(20), grade VARCHAR(20), score INT, PRIMARY KEY (sno, coursename) ); -- 獎(jiǎng)懲信息表 CREATE TABLE jc ( sname VARCHAR(20) NOT NULL, grade VARCHAR(20), jdate DATE, jname VARCHAR(30), jmemo VARCHAR(100), PRIMARY KEY (sname, jdate) ); -- 用戶表 CREATE TABLE user ( username CHAR(20) NOT NULL, password CHAR(20) NOT NULL, role CHAR(10) DEFAULT student, PRIMARY KEY (username) );這段腳本跟報(bào)告原文的差異主要有四處第一所有拼寫錯(cuò)誤修正第二student表里把saddree拆成了sbirthday出生日期和saddress家庭住址因?yàn)樵陌褍蓚€(gè)語義完全不同的字段混用了一個(gè)名字第三class.number改成INT并給了默認(rèn)值 0第四jc表的主鍵從單獨(dú)的sname改成sname jdate聯(lián)合主鍵因?yàn)橐粋€(gè)學(xué)生可能有多條獎(jiǎng)懲記錄只用姓名做主鍵會(huì)導(dǎo)致第二條記錄插不進(jìn)去。3.2 參照完整性約束怎么加報(bào)告里提到了「建立數(shù)據(jù)庫相關(guān)表之間的參照完整性約束」但原文的建表語句里一個(gè)外鍵都沒寫。參照完整性說白了就是外鍵約束保證學(xué)生表里的班級(jí)名在班級(jí)表里一定存在成績表里的學(xué)號(hào)在學(xué)生表里一定存在。加外鍵有兩種方式建表時(shí)用FOREIGN KEY子句或者建表后用ALTER TABLE追加。我一般推薦建完表統(tǒng)一加方便調(diào)整順序-- 學(xué)生表的班級(jí)名參照班級(jí)表 ALTER TABLE student ADD CONSTRAINT fk_student_class FOREIGN KEY (classname) REFERENCES class(classname) ON UPDATE CASCADE ON DELETE SET NULL; -- 成績表的學(xué)號(hào)參照學(xué)生表 ALTER TABLE score ADD CONSTRAINT fk_score_student FOREIGN KEY (sno) REFERENCES student(sno) ON DELETE CASCADE; -- 成績表的課程名參照課程表 ALTER TABLE score ADD CONSTRAINT fk_score_course FOREIGN KEY (coursename) REFERENCES course(coursename) ON UPDATE CASCADE;ON UPDATE CASCADE的意思是班級(jí)名改了學(xué)生表里對(duì)應(yīng)的班級(jí)名自動(dòng)跟著改ON DELETE SET NULL是班級(jí)刪了學(xué)生表里的班級(jí)名置空而不是刪學(xué)生ON DELETE CASCADE是學(xué)生刪了他的成績記錄也跟著刪。這三個(gè)策略要根據(jù)業(yè)務(wù)規(guī)則來選不是隨便加的。比如學(xué)生轉(zhuǎn)班只改班級(jí)名用 CASCADE 就很省事但班級(jí)撤銷了不能把學(xué)生也刪了所以用 SET NULL。注意加外鍵之前要確保兩張表的字段類型完全一致。比如student.classname是VARCHAR(20)class.classname也必須是VARCHAR(20)一個(gè) CHAR 一個(gè) VARCHAR 在某些數(shù)據(jù)庫里會(huì)直接拒絕創(chuàng)建外鍵。4. 視圖、觸發(fā)器、存儲(chǔ)過程報(bào)告里最值錢的三個(gè)模塊4.1 視圖定義與查詢封裝報(bào)告里創(chuàng)建了一個(gè)student_view把學(xué)生表的所有字段包進(jìn)去。原文的寫法是Create view student_view(...) as select * from student這個(gè)視圖本身沒什么過濾邏輯實(shí)際價(jià)值不大。但視圖的真正用途是封裝復(fù)雜查詢比如「查詢學(xué)生的學(xué)號(hào)、姓名、性別、院系、專業(yè)、班級(jí)信息」這個(gè)需求需要 join 學(xué)生表和班級(jí)表CREATE VIEW v_student_full AS SELECT s.sno AS 學(xué)號(hào), s.sname AS 姓名, s.ssex AS 性別, c.tdepartment AS 院系, s.sspeciality AS 專業(yè), s.classname AS 班級(jí) FROM student s LEFT JOIN class c ON s.classname c.classname;這個(gè)視圖的好處是前端查詢直接SELECT * FROM v_student_full WHERE 院系 計(jì)算機(jī)系就行不用每次寫 join。LEFT JOIN保證即使學(xué)生還沒分配班級(jí)學(xué)生記錄也能查出來班級(jí)字段顯示 NULL。4.2 觸發(fā)器自動(dòng)維護(hù)班級(jí)人數(shù)報(bào)告里最核心的技術(shù)點(diǎn)就是「當(dāng)新增、修改或刪除學(xué)生時(shí)自動(dòng)修改相應(yīng)班級(jí)的學(xué)生人數(shù)」。原文寫了兩個(gè)觸發(fā)器insert_number和dele_number但語法問題很多declare sno int在 MySQL 里不合法set sno(select sno from deleted)這種寫法在 SQL Server 里才成立而且sno是 CHAR 類型不是 INT。下面是我改寫成 MySQL 語法的版本用AFTER INSERT和AFTER DELETE兩個(gè)觸發(fā)器實(shí)現(xiàn)DELIMITER $$ -- 新增學(xué)生時(shí)班級(jí)人數(shù) 1 CREATE TRIGGER trg_student_insert AFTER INSERT ON student FOR EACH ROW BEGIN UPDATE class SET number number 1 WHERE classname NEW.classname; END$$ -- 刪除學(xué)生時(shí)班級(jí)人數(shù) -1 CREATE TRIGGER trg_student_delete AFTER DELETE ON student FOR EACH ROW BEGIN UPDATE class SET number number - 1 WHERE classname OLD.classname; END$$ -- 修改學(xué)生班級(jí)時(shí)舊班級(jí) -1新班級(jí) 1 CREATE TRIGGER trg_student_update AFTER UPDATE ON student FOR EACH ROW BEGIN IF OLD.classname NEW.classname THEN UPDATE class SET number number - 1 WHERE classname OLD.classname; UPDATE class SET number number 1 WHERE classname NEW.classname; END IF; END$$ DELIMITER ;三個(gè)觸發(fā)器的邏輯說明NEW代表插入或修改后的新行OLD代表刪除或修改前的舊行。插入時(shí)用NEW.classname找到班級(jí)加一刪除時(shí)用OLD.classname找到班級(jí)減一修改時(shí)要判斷班級(jí)是否變了變了才做一減一加沒變就不動(dòng)。DELIMITER $$是因?yàn)橛|發(fā)器體里有分號(hào)需要臨時(shí)改分隔符不然 MySQL 會(huì)在第一個(gè)分號(hào)處截?cái)?。提示觸發(fā)器是「隱形」的邏輯調(diào)試的時(shí)候如果班級(jí)人數(shù)對(duì)不上先查student表里有沒有班級(jí)名為 NULL 的記錄再查觸發(fā)器有沒有被正確創(chuàng)建。SHOW TRIGGERS;可以列出當(dāng)前庫所有觸發(fā)器。4.3 存儲(chǔ)過程統(tǒng)計(jì)各院系男女人數(shù)報(bào)告里的存儲(chǔ)過程number用了Return(select count(...))的寫法這個(gè)在標(biāo)準(zhǔn) SQL 里不成立RETURN只能返回一個(gè)值不能返回結(jié)果集。正確做法是用SELECT直接輸出結(jié)果或者用OUT參數(shù)。我改成 MySQL 的存儲(chǔ)過程DELIMITER $$ CREATE PROCEDURE sp_count_gender(IN p_classname VARCHAR(20)) BEGIN SELECT SUM(CASE WHEN ssex 男 THEN 1 ELSE 0 END) AS 男生人數(shù), SUM(CASE WHEN ssex 女 THEN 1 ELSE 0 END) AS 女生人數(shù), COUNT(*) AS 總?cè)藬?shù) FROM student WHERE classname p_classname; END$$ DELIMITER ;調(diào)用方式CALL sp_count_gender(計(jì)軟2101);。這個(gè)存儲(chǔ)過程用CASE WHEN做條件計(jì)數(shù)比報(bào)告里寫兩個(gè)Return要靠譜得多。參數(shù)p_classname是輸入?yún)?shù)調(diào)用時(shí)傳入班級(jí)名即可。如果你要統(tǒng)計(jì)的是院系而不是班級(jí)把WHERE classname p_classname改成 join 班級(jí)表按tdepartment過濾就行。4.4 CHECK 約束和性別限制報(bào)告里用CONSTRAINT C4 CHECK(Ssex IN(男,女))來限制性別輸入。這個(gè)約束在 MySQL 8.0.16 之后才真正生效之前的版本會(huì)解析但忽略。如果你用的是 MySQL 5.7CHECK 約束不會(huì)報(bào)錯(cuò)但也不會(huì)攔截非法數(shù)據(jù)需要改用觸發(fā)器來實(shí)現(xiàn)-- MySQL 5.7 用觸發(fā)器替代 CHECK DELIMITER $$ CREATE TRIGGER trg_check_sex BEFORE INSERT ON student FOR EACH ROW BEGIN IF NEW.ssex NOT IN (男, 女) THEN SIGNAL SQLSTATE 45000 SET MESSAGE_TEXT 性別只能輸入男或女; END IF; END$$ DELIMITER ;SIGNAL SQLSTATE 45000是 MySQL 里主動(dòng)拋異常的標(biāo)準(zhǔn)寫法插入非法性別時(shí)會(huì)直接報(bào)錯(cuò)并回滾。SQL Server 用戶直接用CHECK約束就行SQL Server 對(duì) CHECK 的支持一直很完整。5. 避坑與排查這份報(bào)告里最容易翻車的五個(gè)地方5.1 觸發(fā)器報(bào)錯(cuò)「Cant update table in stored function/trigger」現(xiàn)象創(chuàng)建觸發(fā)器后插入學(xué)生記錄時(shí)報(bào)錯(cuò)提示不能在觸發(fā)器里更新被觸發(fā)的表。原因MySQL 不允許在觸發(fā)器里更新觸發(fā)器所在的那張表。比如你在student表的觸發(fā)器里寫UPDATE student SET ...就會(huì)觸發(fā)這個(gè)錯(cuò)誤。報(bào)告原文的觸發(fā)器里沒有這個(gè)問題但如果你自己擴(kuò)展邏輯時(shí)不小心寫了對(duì)student表的更新就會(huì)翻車。解決把要更新的邏輯挪到另一張表上或者用存儲(chǔ)過程替代觸發(fā)器。如果確實(shí)需要更新同一張表用BEFORE觸發(fā)器配合SET NEW.字段 值的方式而不是UPDATE語句。5.2 班級(jí)人數(shù)越跑越多或變成負(fù)數(shù)現(xiàn)象反復(fù)插入刪除學(xué)生后class.number跟實(shí)際學(xué)生數(shù)對(duì)不上要么多了要么少了。原因三種可能。一是觸發(fā)器只建了 INSERT 沒建 DELETE刪學(xué)生時(shí)人數(shù)不減二是修改學(xué)生班級(jí)時(shí)沒有處理舊班級(jí)的減一三是直接手動(dòng)改了student表的數(shù)據(jù)但觸發(fā)器沒覆蓋到那條路徑。解決先SELECT classname, COUNT(*) FROM student GROUP BY classname;查出真實(shí)人數(shù)再UPDATE class SET number (SELECT COUNT(*) FROM student WHERE student.classname class.classname);校準(zhǔn)一次。然后檢查三個(gè)觸發(fā)器INSERT/DELETE/UPDATE是否都建了。我一般會(huì)在建完觸發(fā)器后跑一輪增刪改測試確認(rèn)人數(shù)變化符合預(yù)期再繼續(xù)。5.3 外鍵約束導(dǎo)致建表順序報(bào)錯(cuò)現(xiàn)象執(zhí)行建表腳本時(shí)score表創(chuàng)建失敗提示「Cannot add foreign key constraint」。原因外鍵引用的表還沒建。比如score表引用了student和course如果先建score再建student外鍵就找不到目標(biāo)表。另外字段類型不匹配也會(huì)導(dǎo)致這個(gè)錯(cuò)誤比如student.sno是CHAR(15)score.sno寫成了VARCHAR(15)。解決建表順序按依賴關(guān)系來——先建class和course再建student最后建score和jc?;蛘呦冉ㄋ斜聿患油怄I最后統(tǒng)一用ALTER TABLE追加。字段類型用SHOW CREATE TABLE student;核對(duì)一遍確保跟外鍵定義完全一致。5.4 存儲(chǔ)過程參數(shù)傳中文亂碼現(xiàn)象調(diào)用CALL sp_count_gender(計(jì)軟2101);返回空結(jié)果但表里明明有這個(gè)班級(jí)的數(shù)據(jù)。原因數(shù)據(jù)庫、表、連接三層的字符集不一致。常見情況是數(shù)據(jù)庫建的時(shí)候用了latin1表用了utf8客戶端連接又用了gbk中文參數(shù)傳到存儲(chǔ)過程里就變成了亂碼匹配不上任何記錄。解決建庫時(shí)統(tǒng)一用utf8mb4連接字符串里加characterEncodingutf8。已經(jīng)建好的庫可以用ALTER DATABASE student_db CHARACTER SET utf8mb4;和ALTER TABLE student CONVERT TO CHARACTER SET utf8mb4;修正。存儲(chǔ)過程參數(shù)定義里也要顯式寫VARCHAR(20) CHARACTER SET utf8mb4。5.5 視圖查詢權(quán)限不足現(xiàn)象用普通用戶賬號(hào)查詢v_student_full時(shí)報(bào)錯(cuò)「SELECT command denied」。原因視圖的權(quán)限跟基表是分開的。即使用戶對(duì)student和class表有查詢權(quán)限如果沒有單獨(dú)授予視圖的SELECT權(quán)限照樣查不了。另外如果視圖定義里用了DEFINER執(zhí)行時(shí)是以定義者的身份運(yùn)行定義者沒有權(quán)限也會(huì)失敗。解決用管理員賬號(hào)執(zhí)行GRANT SELECT ON student_db.v_student_full TO 用戶名localhost;。如果視圖用了SQL SECURITY DEFINER改成SQL SECURITY INVOKER讓視圖以調(diào)用者身份執(zhí)行權(quán)限模型會(huì)更清晰。6. 進(jìn)階驗(yàn)證用一組測試數(shù)據(jù)把整條鏈路跑通建完表、加完約束、寫完觸發(fā)器和存儲(chǔ)過程之后別急著交報(bào)告。我一般會(huì)灌一組測試數(shù)據(jù)把增刪改查和統(tǒng)計(jì)邏輯全部走一遍確認(rèn)沒有玄學(xué)問題。下面這套驗(yàn)證腳本你可以直接抄-- 1. 插入班級(jí) INSERT INTO class VALUES (計(jì)軟2101, 計(jì)算機(jī)系, 張老師, A101, 0); INSERT INTO class VALUES (計(jì)軟2102, 計(jì)算機(jī)系, 李老師, A102, 0); -- 2. 插入學(xué)生觸發(fā)器應(yīng)自動(dòng)把班級(jí)人數(shù)改成 2 和 1 INSERT INTO student (sno, sname, ssex, classname) VALUES (2021001, 張三, 男, 計(jì)軟2101); INSERT INTO student (sno, sname, ssex, classname) VALUES (2021002, 李四, 女, 計(jì)軟2101); INSERT INTO student (sno, sname, ssex, classname) VALUES (2021003, 王五, 男, 計(jì)軟2102); -- 3. 驗(yàn)證班級(jí)人數(shù) SELECT classname, number FROM class; -- 預(yù)期計(jì)軟2101 2計(jì)軟2102 1 -- 4. 插入課程和成績 INSERT INTO course (cid, coursename) VALUES (C001, 數(shù)據(jù)庫原理); INSERT INTO score (sno, coursename, sname, score) VALUES (2021001, 數(shù)據(jù)庫原理, 張三, 88); INSERT INTO score (sno, coursename, sname, score) VALUES (2021002, 數(shù)據(jù)庫原理, 李四, 92); -- 5. 調(diào)用存儲(chǔ)過程統(tǒng)計(jì)男女人數(shù) CALL sp_count_gender(計(jì)軟2101); -- 預(yù)期男生 1 人女生 1 人總計(jì) 2 人 -- 6. 測試 CHECK 約束這條應(yīng)該報(bào)錯(cuò) INSERT INTO student (sno, sname, ssex, classname) VALUES (2021004, 趙六, 未知, 計(jì)軟2101); -- 預(yù)期報(bào)錯(cuò)性別只能輸入男或女 -- 7. 測試刪除觸發(fā)器 DELETE FROM student WHERE sno 2021003; SELECT classname, number FROM class WHERE classname 計(jì)軟2102; -- 預(yù)期計(jì)軟2102 人數(shù)變成 0 -- 8. 測試修改觸發(fā)器學(xué)生轉(zhuǎn)班 UPDATE student SET classname 計(jì)軟2102 WHERE sno 2021001; SELECT classname, number FROM class; -- 預(yù)期計(jì)軟2101 變成 1計(jì)軟2102 變成 1這套腳本跑完如果每一步的結(jié)果都跟預(yù)期一致說明你的表結(jié)構(gòu)、約束、觸發(fā)器、存儲(chǔ)過程全部正確。如果有哪一步不對(duì)回到對(duì)應(yīng)的章節(jié)排查。最后說一個(gè)我自己的習(xí)慣每次交課設(shè)之前我都會(huì)把整個(gè)建庫腳本刪庫重跑一遍從DROP DATABASE IF EXISTS student_db;開始確保腳本是冪等的、不依賴任何手工操作。這個(gè)習(xí)慣幫我抓出過好幾次「本地能跑、換臺(tái)機(jī)器就報(bào)錯(cuò)」的問題。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取