资讯动态

数据库实验报告拆解:SQL建表、查询与完整性复习地图

发布时间:2026/10/27 3:01:36 来源:尧图企业网站定制
简介面向太原理工大学软件工程专业数据库概论课程的实验报告文档适合正在学习数据库系统原理、需要完成SQL上机实验或复盘课堂操作的学生参考。内容围绕Microsoft SQL Server 2016环境展开覆盖基本表的创建、修改与删除索引与视图的建立以及插入、更新、查询等数据操作并涉及数据完整性、用户鉴别与数据控制等实验主题能帮助读者理清实验步骤与SQL语句的对应关系。资源包共1个docx文件大小约1.69MB以实验报告正文形式组织便于直接查阅实验目的、平台配置、主要实验内容及结果记录。目前已有311人学习下载。读者可从中获得较完整的实验过程样例、SQL语法示例与结果验证思路用于对照自己的建表、索引、视图和更新操作查漏补缺并理解数据完整性约束在实践中的落地方式。1. 数据库实验的知识地图一份实验报告能拆出多少考点软件工程专业学数据库最后大多要交一份实验报告几十条 SQL、一个学生选课库、两三张结果截图。很多人写完就丢进硬盘深处等到复习才发现这东西其实是一张现成的知识地图——数据定义、数据更新、数据查询、数据完整性、访问控制五块内容是混在一起写的而考场上它们是分开问的。这份笔记做的事就是把那份混着写的实验报告重新切开、按模块码齐先讲表、索引、视图这些“架子”怎么搭再讲增删改查这条主链路然后是约束、触发器、权限这三道完整性关卡最后收到一张能自测的复习清单。它适合正在系统学数据库的人当地图用也适合考前想快速查漏补缺的人对着目录翻。提前说一句读的时候手边开着查询编辑器看到语句就敲一遍比读三遍管用。2. 数据定义与对象管理建表、改表、索引三件事数据定义是整份实验报告的地基也是最容易被“跑通了就行”糊弄过去的一段。建表语句写得糙后面所有更新、查询、约束验证都会跟着别扭。这一章把三张核心表、四类 ALTER 动作、三种索引和视图放一起对照搞清楚每一步为什么这么写。2.1 三张表的骨架主键、外键、CHECK 与 DEFAULT 怎么摆学生选课库是数据库课的万能模型Student存人Course存课SC存“谁选了什么、考了多少分”。三张表的难点不在字段多少而在约束往哪儿放。-- 学生表实体完整性靠主键用户定义完整性靠 CHECK 和 DEFAULT CREATE TABLE Student ( Sno CHAR(8) PRIMARY KEY, -- 主键唯一且非空 Sname CHAR(8) NOT NULL, -- 姓名不允许为空 Ssex CHAR(2) CHECK (Ssex IN (男,女)), -- 取值域限制 Sage SMALLINT, Sdept CHAR(20), Sclass CHAR(4) NOT NULL, Stotal SMALLINT DEFAULT 0 -- 不写值时自动填 0 ); -- 课程表约束显式命名后面想删才有名字可用 CREATE TABLE Course ( Cno CHAR(4) CONSTRAINT PK_Course PRIMARY KEY, Cname CHAR(40), Cpno CHAR(4), -- 先修课指向本表 Cno Ccredit SMALLINT ); -- 选课表复合主键 两个外键 成绩区间校验 CREATE TABLE SC ( Sno CHAR(8) REFERENCES Student(Sno), -- 列级外键的写法 Cno CHAR(4), Grade SMALLINT CONSTRAINT SC_CHECK CHECK (Grade 0 AND Grade 100), PRIMARY KEY (Sno, Cno), -- 同一个学生同一门课只能一条 CONSTRAINT FK_SC FOREIGN KEY (Cno) REFERENCES Course(Cno) );三张表的角色分工值得单独记一句Student和Course是“被引用方”SC是“引用方”所以外键只出现在SC上SC的主键是复合的(Sno, Cno)这决定了它天然能防止重复选课也决定了后面插入时两个列都不能为空。提示列级外键的标准写法是Sno CHAR(8) REFERENCES Student(Sno)。把FOREIGN KEY (Sno) REFERENCES ...塞进列定义里是语法错误FOREIGN KEY关键字只属于表级约束。这个坑在交作业时特别常见因为两种写法看起来只差几个字。约束命名也是一门小学问。CONSTRAINT PK_Course PRIMARY KEY和直接PRIMARY KEY效果一样但前者在系统里留下了名字后面ALTER TABLE ... DROP CONSTRAINT PK_Course才有东西可删。默认命名的约束像CK__SC__Grade__1A2B3C4D这种你根本背不下来改约束时只能先去查系统视图。2.2 ALTER TABLE 的四类动作与执行顺序陷阱建完表之后结构往往还要动实验报告里通常会出现四类动作每一类对应一个真实需求动作语法形态典型场景加列ALTER TABLE 表 ADD 列 类型学生表补一个班级字段改列类型ALTER TABLE 表 ALTER COLUMN 列 新类型Sage从INT收窄为SMALLINT加约束ALTER TABLE 表 ADD UNIQUE(列)/ADD FOREIGN KEY ...课程名唯一、先修课自引用删约束ALTER TABLE 表 DROP CONSTRAINT 约束名把成绩区间从开区间改成闭区间-- 加列新列默认允许 NULL所以老数据不会报错 ALTER TABLE Student ADD Sclass CHAR(4); -- 改类型从 INT 收到 SMALLINT 属于收窄超出范围的老数据会直接失败 ALTER TABLE Student ALTER COLUMN Sage SMALLINT; -- 课程名加唯一约束防止同名课程重复录入 ALTER TABLE Course ADD UNIQUE (Cname); -- 先修课自引用Cpno 指向本表的 Cno ALTER TABLE Course ADD FOREIGN KEY (Cpno) REFERENCES Course(Cno);这几条语句单看都简单麻烦在顺序。加了Sclass列之后才能在SELECT里引用它SC表的Grade约束如果一开始写成Grade 0 AND Grade 100那 0 分和 100 分都插不进去必须先把旧约束DROP掉再重建ALTER TABLE SC DROP CONSTRAINT SC_CHECK; ALTER TABLE SC ADD CONSTRAINT SC_CHECK CHECK (Grade 0 AND Grade 100);改类型这一步要额外留个心ALTER COLUMN在数据量大的表上可能触发表重建收窄类型还可能截断或报错。实验环境里几百行数据感觉不到换到真实库就是血泪经验。2.3 索引唯一、聚簇、复合与排序方向索引在实验里通常只占三五行但它是“为什么有的查询快”的唯一答案。四类索引各有各的适用面-- 普通索引加速按课程名的等值和范围查询 CREATE INDEX iCname ON Course(Cname); -- 唯一索引既加速又保证取值不重复 CREATE UNIQUE INDEX iSname ON Student(Sname); -- 聚簇索引决定数据行的物理排列顺序一张表只能有一个 CREATE CLUSTERED INDEX iSnoCno ON SC(Sno, Cno DESC); -- 唯一索引也可以用约束的方式建二者底层等价 CREATE UNIQUE INDEX iCno ON Course(Cno);iSnoCno这条最值得拆开看。它是复合索引索引键是(Sno, Cno DESC)意味着按学号升序、同学号内按课程号降序排列。查询WHERE Sno 20210001能吃到它最左前缀原则只查WHERE Cno 1就吃不到——这就是复合索引“最左列不参与就白搭”的规则。DESC影响的是扫描方向对ORDER BY Sno, Cno DESC这类排序能省掉一次排序步骤。聚簇索引的限制也要记牢一张表只能有一个因为数据行只能有一种物理顺序。SC表把它建在(Sno, Cno)上等于让同一学生的选课记录在磁盘上扎堆查“某学生选了哪些课”时一次页读取就够。反过来如果聚簇索引建在别的列上再想按学号聚簇就没机会了。注意索引不是越多越好。每个索引在插入、更新、删除时都要同步维护写多读少的表上堆索引纯属自找麻烦区分度低的列比如性别只有两个取值建索引基本不划算。2.4 视图把复杂连接封成一个名字视图是虚表本身不存数据只保存一条查询定义。实验报告里常见的三种视图分别对应三种需求单表投影、聚合汇总、多表连接。-- 需求一只看信息系学生的学号、姓名、年龄 CREATE VIEW IS_Student AS SELECT Sno, Sname, Sage FROM Student WHERE Sdept IS; -- 注意原文这里少了一个右引号 -- 需求二每个学生的平均分列名重命名让结果更好读 CREATE VIEW S_G (Sno, Gavg) AS SELECT Sno, AVG(Grade) FROM SC GROUP BY Sno; -- 需求三把三表连接封起来以后查选课明细不用再写 JOIN CREATE VIEW XK_VIEW AS SELECT Student.Sno, Sname, Course.Cno, Cname, Grade FROM Student, SC, Course WHERE Student.Sno SC.Sno AND SC.Cno Course.Cno;建完之后SELECT * FROM IS_Student就能当普通表用这是视图最直接的价值把三表连接这种一写就错的语句固定下来调用方只需要记住一个名字。视图的可更新性是个高频考点。单表投影、不含聚合和DISTINCT的视图一般可以增删改带GROUP BY、聚合函数、DISTINCT、集合运算的视图比如S_G不可更新因为一条视图记录对应的是多行基表数据的汇总数据库没法反推该改哪一行。3. 数据更新与查询从 INSERT 到嵌套子查询的完整链路这一章是整份实验报告里篇幅最大的部分也是考试分值最集中的地方。按“写进去、改掉、删掉、查出来”的顺序走一遍比零散背语法有效得多。3.1 插入的三种写法与 SELECT INTO 建临时表插入看似只有一条INSERT实际有四种变体用错了就是约束报错或者列错位-- 写法一全列插入值的顺序必须和表定义完全一致 INSERT INTO Student VALUES (20210001,林一,男,20,CS,1001,0); -- 写法二指定列插入允许空值的列可以省略走默认值或 NULL INSERT INTO Student (Sno, Sname, Ssex, Sclass) VALUES (20210002,周迟,女,1001); -- 写法三插入 NULL 要显式写 NULL不能靠省略 INSERT INTO Student VALUES (20210003,陈舟,女,NULL,NULL,1001,0); -- 写法四从查询结果批量插入一次搬一整批数据 INSERT INTO cs_Student (学号, 姓名, 年龄) SELECT Sno, Sname, Sage FROM Student WHERE Sdept CS;写法四特别值得记因为两个细节容易漏目标表的列顺序和SELECT的列顺序是按位置对应的名字对不对得上反而不重要INSERT INTO ... SELECT不加VALUES关键字加了就报错。SELECT INTO是另一条路它会在插入的同时新建表-- 把选课数据整体复制成一张临时表方便做“删除演练” SELECT * INTO tmpSC FROM SC;这条语句的特点是目标表不能事先存在字段类型和名字从查询结果推导。实验里用它来练删除最合适——删坏了重新SELECT INTO一遍就行不会污染原始数据。3.2 UPDATE 与 DELETE子查询做条件时的两种写法单条件更新没什么好说的真正容易出错的是“条件在别的表里”。这时候有两种写法一种用标量子查询一种用相关子查询-- 标量子查询先把系名查出来再当作等值条件 UPDATE SC SET Grade Grade 5 WHERE CS (SELECT Sdept FROM Student WHERE Student.Sno SC.Sno); -- 相关子查询子查询里的 SC.Sno 来自外层正在更新的那一行 UPDATE SC SET Grade 80 WHERE Cno 2 AND Sno (SELECT Sno FROM Student WHERE Sname 周迟);两条语句的关键差别在于关联列的位置。第二条里子查询(SELECT Sno FROM Student WHERE Sname 周迟)返回的是单值所以能用如果姓名不唯一子查询返回多行直接报错得换成IN。这是标量子查询最常见的运行时错误。删除的语法更简单风险反而更大-- 有条件删除删掉某学生的某门选课记录 DELETE FROM SC WHERE Sno 20210001 AND Cno 1; -- 无条件删除清空整表表结构还在自增种子会重置 DELETE FROM tmpSC;DELETE FROM 表不带WHERE就是全删这个动作在实验里是刻意演示在真实库上就是事故。区分一下DELETE是逐行删、记日志、可回滚TRUNCATE TABLE是整页释放、不记行日志、速度快但不可回滚DROP TABLE连表结构一起没。三者不是一回事。还有一个连锁反应值得提前知道UPDATE Student SET Sno 20210025 WHERE Sno 20210021这种改主键的操作如果SC表里有对应外键记录且外键没声明ON UPDATE CASCADE语句会直接失败。想改主键要么先删子表记录要么建外键时就带上级联选项。3.3 单表查询条件写法的清单单表查询是分值最稳的一块题目千变万化落到语法上就那么几类谓词。做成一张对照表复习时扫一眼比翻书快需求写法常见翻车去重SELECT DISTINCT Sno FROM SC忘了DISTINCT选课数被算成选课记录数表达式列SELECT Sname, YEAR(GETDATE()) - Sage AS 出生年 FROM Student硬编码年份换一年结果全错列别名Sname AS 姓名/Sname 姓名/姓名 Sname三种写法混用中文别名没加引号报错范围WHERE Sage BETWEEN 20 AND 23以为区间开闭可配实际两端都包含集合WHERE Sdept IN (IS,MA,CS)用OR拼一长串漏括号导致优先级错乱模糊WHERE Sname LIKE 林%%和_混用NOT LIKE的 NULL 行不返回空值WHERE Grade IS NULL写成 NULL永远返回空结果集多重条件WHERE Sdept CS AND Sage 20AND优先级高于OR混用时漏括号排序ORDER BY Sdept, Sage DESC以为DESC管全部列其实只作用于紧跟的那一列前 N 行SELECT TOP 5 * FROM SC ORDER BY Grade DESCTOP不带ORDER BY结果顺序不确定表格里最值得反复看的是IS NULL和 NULL的区别。NULL不是值是“未知”任何和它的比较运算结果都是未知WHERE Grade NULL只会返回空集。同理COUNT(Grade)不统计 NULL 行COUNT(*)才统计。ORDER BY的多列排序也要说清楚ORDER BY Sdept, Sage DESC的语义是“先按系名升序系名相同时按年龄降序”DESC只修饰SageSdept仍然默认升序。想两列都降序得写两遍DESC。3.4 分组统计GROUP BY、HAVING 与聚集函数的执行顺序分组是查询里最抽象的一块抽象的原因是它改变了对“一行”的定义。理解方式就一句GROUP BY之后每一组变成一行SELECT里能出现的只有分组列和聚集函数。-- 按课程分组每组的课程号、人数、均分、最高分 SELECT Cno AS 课程号, COUNT(*) AS 人数, AVG(Grade) AS 均分, MAX(Grade) AS 最高分 FROM SC GROUP BY Cno HAVING AVG(Grade) 85; -- 过滤的是“组”不是“行”这段语句的执行顺序是FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。WHERE在分组前过滤行HAVING在分组后过滤组二者不能互换位置。想在分组前筛掉 NULL 成绩写WHERE Grade IS NOT NULL想筛掉均分不够的课程写HAVING AVG(Grade) 85。聚集函数本身也有讲究写法含义差别COUNT(*)统计行数含 NULL 行COUNT(Grade)统计该列非空值个数跳过 NULLCOUNT(DISTINCT Sno)统计不重复的学号数选课人数不是选课记录数COUNT(*)和COUNT(DISTINCT Sno)的差别在“选课人数”这类题里是送分点也是丢分点一个学生选三门课前者算三条后者算一人。跨表分组时要多留意一句SELECT里的非聚集列必须出现在GROUP BY里。想按班级统计每门课的选课人数就得GROUP BY Sclass, Cno两个列都写上少写一个在很多数据库上直接报错。3.5 连接查询WHERE 连接、JOIN ON、外连接与自连接连接是把散在两张表里的信息拼成一行。同一件事有三种写法语义等价风格不同-- 写法一连接条件写在 WHERE 里隐式连接 SELECT Student.Sno, Sname, Cno, Grade FROM Student, SC WHERE Student.Sno SC.Sno; -- 写法二JOIN ON连接条件和过滤条件分家推荐 SELECT Student.Sno, Sname, Cno, Grade FROM Student JOIN SC ON Student.Sno SC.Sno WHERE SC.Grade 85; -- 过滤条件单独放 WHERE -- 写法三外连接没选课的学生也要出现在结果里 SELECT Student.Sno, Sname, Cno, Grade FROM Student LEFT OUTER JOIN SC ON Student.Sno SC.Sno;三种写法里JOIN ON最值得养成习惯因为连接条件ON和过滤条件WHERE分开了读语句时一眼能看出哪部分是“拼表”、哪部分是“筛行”。隐式连接混着写的时候少写一个连接条件就会退化成笛卡尔积行数瞬间爆炸——这是最典型的一种“结果看着不对劲”。外连接和它的位置强相关LEFT OUTER JOIN保留左表全部行右表没匹配上的补 NULLRIGHT OUTER JOIN反过来。上面第三条语句的结果里没选课的学生Cno和Grade都是 NULL这正是“查没选课的学生”这类题的标准解法。自连接是连接里的进阶用法用来处理“表自己引用自己”的结构。课程表里的Cpno指向本表Cno要求“每门课的间接先修课”就得让课程表和它自己连一次-- first 是当前课程second 是它的先修课再往下找一层就是间接先修课 SELECT first.Cno AS 课程号, second.Cpno AS 间接先修课 FROM Course first, Course second WHERE first.Cpno second.Cno;自连接必须给同一张表起两个别名否则列名没法区分。first.Cpno second.Cno的意思是“第一张表的先修课号等于第二张表的课程号”也就是顺着先修关系往上走一层。3.6 嵌套查询与集合运算IN、比较、ALL/ANY、EXISTS嵌套查询是把一条SELECT的结果当作另一条的条件。按引出方式分四类难度递增-- 一、IN 引出同系学生子查询可能返回多行 SELECT Sno, Sname, Sdept FROM Student WHERE Sdept IN (SELECT Sdept FROM Student WHERE Sname 林一); -- 二、比较运算符 聚集函数每个学生超过自己平均分的课程 SELECT Sno, Cno FROM SC x WHERE Grade (SELECT AVG(Grade) FROM SC y WHERE y.Sno x.Sno); -- 三、ALL比计算机系所有学生年龄都小 SELECT Sname, Sage FROM Student WHERE Sage ALL (SELECT Sage FROM Student WHERE Sdept CS) AND Sdept CS; -- 四、EXISTS只关心“有没有”不关心具体值 SELECT Sname FROM Student WHERE EXISTS (SELECT * FROM SC WHERE SC.Sno Student.Sno AND Cno 1);第二条是相关子查询的典型y.Sno x.Sno里的x来自外层子查询对外层每一行都重新算一次。这类语句的性能陷阱在于很多人会写成不相关的形式然后发现结果不对——AVG(Grade)到底是全表平均还是每人平均全看有没有那个关联条件。第四条里EXISTS的子查询SELECT *不是真的取所有列数据库只判断有没有行所以写SELECT *和SELECT 1没区别。NOT EXISTS常和“全称量词”的题绑在一起比如“选修了全部课程的学生”解法是“不存在一门他没选的课”句式要绕一下。集合运算把两条独立查询的结果按行合并运算关键字语义注意并UNION两结果集合并默认去重要保留重复用UNION ALL交INTERSECT两边都有的行列数和类型必须一一对应差EXCEPT左边有、右边没有顺序敏感A EXCEPT B ≠ B EXCEPT A-- 差集计算机系里年龄大于 19 的学生 SELECT * FROM Student WHERE Sdept CS EXCEPT SELECT * FROM Student WHERE Sage 19;EXCEPT的顺序一定不能反。同一道题写成SELECT * FROM Student WHERE Sage 19 EXCEPT ...结果就变成“年龄小的非计算机系学生”语义完全变了。集合运算对列的要求也比连接严格列数相同、对应列类型兼容SELECT *在两边表结构不一致时会直接报错。4. 数据完整性与访问控制约束、触发器、权限三道关前两章解决“怎么建、怎么改、怎么查”这一章解决“改坏了怎么办”。完整性是数据库课里最像工程实践的一块也是实验报告里最容易只截图不解释的部分。4.1 实体完整性、参照完整性与用户定义完整性怎么落地教材上的三类完整性落到 SQL 上就三种手段一一对应完整性类型保护什么SQL 手段违约时的默认行为实体完整性每行可唯一识别PRIMARY KEY拒绝插入或更新参照完整性外键必须指向存在的行FOREIGN KEY ... REFERENCES拒绝或按级联选项处理用户定义完整性业务规则NOT NULL、UNIQUE、CHECK、DEFAULT拒绝实体完整性靠主键主键天然带唯一和非空两个属性不需要再单独写UNIQUE和NOT NULL。参照完整性靠外键外键的默认行为是“拒绝”——想删被引用的父行先删子行。如果业务上希望自动跟着删就在外键后面加ON DELETE CASCADE这一项在实验里不常用但在真实建模里几乎每张关联表都要想一遍。用户定义完整性最灵活也最容易被忽略边界。CHECK (Grade 0 AND Grade 100)看着合理实际把 0 分和 100 分都挡在外面改成 0 AND 100才和百分制对得上。约束写错方向比如Ssex IN (男,女)写成NOT IN不会报错只会让所有正常数据插不进去。4.2 完整性验证五种故意写错的语句各报什么错实验里最有价值的一步不是建约束而是故意违反约束看系统反应。五类典型操作报错信息各不相同操作预期结果原因插入已存在的Sno失败主键唯一性冲突INSERT INTO SC VALUES(20210001, NULL, 78)失败主键列Cno不允许 NULLUPDATE Student SET Sno 20210021 WHERE Sname 某学生失败新学号已被占用主键冲突插入两门同名课程失败UNIQUE(Cname)冲突插入Grade 105失败CHECK越界插入时省略Stotal成功值为 0DEFAULT 0生效第三行值得多看一眼因为它和“改学号”那类题是同一件事的两种结果改成一个没被占用的新值能成功改成已存在的值就冲突。判断依据只有一条——改完之后主键集合里有没有重复。第二行是复合主键的经典陷阱。SC的主键是(Sno, Cno)两个列合起来构成主键而主键的每一列都不允许为 NULL。所以哪怕Sno有值Cno写 NULL 一样被拒。很多人以为“复合主键可以让某一列为空”恰恰相反复合主键的每一列都是强制非空。4.3 触发器约束表达不了的时候用它约束只能管单行、单表、静态条件。一旦规则跨表或者需要“发生之后再做一件事”就轮到触发器-- 选课记录插入后把该学生的总学分同步累加 CREATE TRIGGER trg_SC_Insert ON SC AFTER INSERT AS BEGIN UPDATE Student SET Stotal ISNULL(Stotal, 0) (SELECT SUM(Ccredit) FROM inserted i JOIN Course c ON i.Cno c.Cno WHERE i.Sno Student.Sno) WHERE Sno IN (SELECT Sno FROM inserted); END;AFTER INSERT表示插入成功之后触发inserted是系统提供的虚拟表装着这次插入的所有新行。触发器里必须按“批量”思维写一次插入多行时inserted里就有多行用去等一个值会漏数据——这是触发器最常见的翻车点。触发器能做的事很多但用它的门槛也该高一点它隐式执行、难调试、嵌套触发容易形成链式反应排错时基本属于黑匣子。能用约束表达就别上触发器这句话在实验报告里写不出来在真实项目里是硬规矩。4.4 用户鉴别与数据控制登录名、数据库用户与 GRANT/REVOKE实验题目里常出现“用户鉴别与数据控制”这一项正文往往只做了约束部分。这一块按通用 SQL 标准补齐逻辑分三层登录身份进服务器、数据库用户映射进来、角色和权限决定能干什么。-- 第一层服务器级登录名 CREATE LOGIN stu_reader WITH PASSWORD Abc123456; -- 第二层映射为当前库的数据库用户 CREATE USER stu_reader FOR LOGIN stu_reader; -- 第三层授权只给查询和插入且允许继续转授 GRANT SELECT, INSERT ON Student TO stu_reader WITH GRANT OPTION; -- 收回权限CASCADE 连带收回对方转授出去的部分 REVOKE INSERT ON Student FROM stu_reader CASCADE;权限语句的重点是几个后缀WITH GRANT OPTION表示被授权人还能把权限转给别人形成授权链REVOKE ... CASCADE会顺着这条链一路收回不写CASCADE而对方已经转授过语句会报错。DENY是另一条独立路径它优先级高于GRANT用来做“整体放开、个别人禁止”的场景。语句作用关键后缀GRANT授予权限WITH GRANT OPTION允许转授REVOKE收回权限CASCADE连带收回下游授权DENY显式拒绝优先级最高压过GRANT最容易被忽略的是“登录名”和“数据库用户”的区别CREATE LOGIN是服务器层面的身份CREATE USER才是某个库里的账户两步都做完权限才有落点。5. 易错点复盘五个最容易翻车的地方实验报告里的错误大体分两类一类会直接报错改起来反而快另一类不报错但结果是错的交上去自己都看不出来。下面五条都是第二类居多按「易漏点 → 为什么漏 → 怎么补」拆开写。5.1 易漏点一ALTER 加列与后续语句的先后顺序为什么漏实验报告是分节写的建表一节、查询一节中间隔着半页纸。加Sclass列的那条ALTER TABLE如果放在查询之后或者干脆漏写所有引用Sclass的分组查询都会报“列名无效”。更隐蔽的是先建了表却没加列然后INSERT里带着 6 个值去插 7 列的表报的是列数不匹配和真正的原因隔了一层。怎么补把脚本按“建表 → 改表 → 插数据 → 查询”固定成四段任何时候重跑都从头执行一遍。写完立刻用SELECT * FROM 表看一眼实际结构别凭记忆判断有哪些列。引用某个列之前先在脚本里能搜到它被创建的那一行。5.2 易错点二CHECK 的边界值把 0 分和 100 分挡在门外为什么漏写约束时脑子里的语义是“成绩在 0 到 100 之间”手上一顺手就写成 0 AND 100。开区间和闭区间差两个符号测试数据又恰好都是 80 多分一路绿灯直到某天要插一个满分记录才炸。怎么补凡是区间约束先问一句“端点算不算”。成绩、年龄、折扣率这类业务量端点通常都要包含写 ... AND ...。建完约束立刻用边界值试三次最小值、最大值、越界值三次结果都对才算这条约束写完了。5.3 易错点三主键列写 NULL 与“复合主键能不能部分为空”为什么漏直觉上“复合主键是两个列合起来唯一”于是很自然地以为单个列可以为空、只要组合不重复就行。实际规则是主键的每一列都强制非空INSERT INTO SC VALUES(20210001, NULL, 78)会直接被拒。怎么补记住一句话——主键 唯一 非空复合主键是每个分量都唯一非空。如果业务上确实需要“某一列可空”的唯一性那是UNIQUE约束的活不是主键的活。测试时专门插一条带 NULL 主键的记录确认系统拒绝。5.4 易错点四UPDATE/DELETE 少了 WHERE 或者关联列写错为什么漏UPDATE SC SET Grade 80这样的语句在语法上完全正确执行也不报错只是把整张表的成绩全改成了 80。另一种是相关子查询里关联列写错比如把Student.Sno SC.Sno写成Student.Sno Student.Sno子查询退化成常量判断结果要么全中要么全不中。怎么补养成“先 SELECT 后 UPDATE”的习惯——把UPDATE的WHERE原样搬到SELECT里跑一遍看行数和内容对不对再执行修改。改之前先SELECT COUNT(*)记下目标行数改完对比受影响行数。涉及子查询的语句把子查询单独拎出来跑一次确认它返回的是单值还是多行。5.5 易错点五GROUP BY 里塞进非分组列、列名拼写与硬编码常量为什么漏SELECT Sname, AVG(Grade) FROM SC GROUP BY Sno这类语句在部分数据库上不报错只是Sname的取值毫无意义每组随机返回一行。再叠加两类低级错误表名拼成Sudent、列名Grade写成Score、出生年份写死成2004 - Sage——拼写错误会报错还算好硬编码年份不报错只是每年都算错。怎么补SELECT里的非聚集列逐个核对是否出现在GROUP BY中缺一个就补一个别指望数据库替你选。年龄和出生年份一律用YEAR(GETDATE()) - Sage这类函数算不写死常量。整段脚本跑之前先在编辑器里过一遍红色波浪线把表名、列名和实际结构对齐。6. 复习清单与查漏补缺把实验报告变成一张自测表到了收尾这一步最有效的做法不是重读一遍报告而是把它改造成一张能自测的表。下面这张清单按模块列了自测问题和掌握标准遮住右列自问一遍答不上来的就是当天要补的洞。模块自测问题掌握标准数据定义三张表的主键、外键、CHECK、DEFAULT 分别在哪能默写出建表语句并说清每条约束防的是什么ALTER加列、改类型、加约束、删约束各一条语法能说清执行顺序为什么不能颠倒索引聚簇索引为什么只能有一个复合索引的最左前缀能判断给定查询能不能吃到某个索引视图哪类视图可更新哪类不可能举出GROUP BY视图不可更新的理由更新INSERT ... SELECT与SELECT INTO的区别能说清前者要求目标表已存在查询WHERE和HAVING的分工COUNT(*)与COUNT(列)的差别能写出带HAVING的分组语句并解释执行顺序连接内连接三种写法、外连接补 NULL、自连接要别名能判断一条语句会不会退化成笛卡尔积嵌套IN、比较、ALL、EXISTS各适合什么题能识别相关子查询的关联列在哪完整性三类完整性对应的 SQL 手段能预测五种违约操作分别报什么错权限GRANT、REVOKE、DENY的优先级能说清WITH GRANT OPTION和CASCADE的连带效果比表格更实用的是一个十五分钟的动手流程新建一个空库不看报告凭记忆把三张表建出来跑五条故意违规的插入逐条预测报错再验证写一条三表连接加分组的统计语句最后用LEFT JOIN找出没选课的学生。四步做完哪一步卡住就翻回对应那一章。这比从头读一遍原文高效得多因为读的时候大脑会骗你说“这个我会”敲的时候不会。还有一个收尾细节把整份脚本从头到尾连续跑一遍。分段执行时前面的DROP、ALTER造成的状态变化会被掩盖连续跑才会暴露顺序依赖——比如某条SELECT引用了三步之后才加的列。连续跑通之后把脚本按模块加注释分段保存以后复习直接按段执行哪段报错就说明哪块忘了。我自己第一次整理这份东西的时候是考前一天把报告从头翻到尾觉得每条语句都眼熟合上电脑却写不出一条完整的三表连接。后来改了个习惯每次复习数据库先关掉所有资料白纸上默写建表和一条分组查询写完再对照。默写不出来的地方才是真正的盲区看着眼熟的那些多半只是眼熟。从那以后我每次碰数据库相关的复习都强制走一遍“空库建表 违规插入 三表查询”这三步比刷十页选择题踏实。希望这套拆法帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑