简介:这份资源是太原理工大学软件工程专业「数据库概论」课程的实验报告,面向正在学习数据库系统原理、需要完成SQL上机实验的本科生与自学者。报告以Microsoft SQL Server 2016为平台,围绕交互式SQL语句的使用展开,涵盖数据定义、索引创建、视图创建与数据操作四大模块,可帮助读者对照完成建表、改表、删表、插入与更新数据等实验任务。压缩包内共1个docx文件,约1.69MB,为完整实验报告文档,包含实验目的、实验平台说明、主要实验内容及结果,并附有Student、Course、Sc、Employee等表的建表语句、索引与视图示例以及多组插入、修改数据的SQL代码。目前已有311人学习下载,适合需要参考实验报告格式、梳理SQL语法要点或查漏补缺的数据库初学者,也可作为课程实验提交前的对照范本。
1. 数据库实验的知识地图:从建表到查询,一份能直接复习的体系笔记
数据库这门课,实验报告写完了不等于真会了。很多人复习时翻着实验报告,发现满篇都是零散的 SQL 语句,脑子里串不起来——建表、约束、索引、视图、查询、更新,这些到底谁先谁后、谁依赖谁、考试和上机最容易在哪翻车,完全没有一张地图。这份笔记就是来解决这个问题的。它把「交互式 SQL 语句的使用」「数据完整性」「用户鉴别与数据控制」三大实验模块重新拆解成一条主线:先定义结构(表、约束、索引、视图),再操作数据(增删改查),最后用完整性约束和权限控制兜底。适合正在系统学数据库、准备实验考或期末复习的人,拿来就能对着查漏补缺。
2. 数据定义与结构设计:建表、约束、索引、视图的复习重点
2.1 建表语句的骨架与字段类型选择
实验里反复出现的CREATE TABLE是所有操作的起点。梳理下来会发现,建表语句的骨架其实就四块:字段名、数据类型、列级约束、表级约束。以 Student 表为例:
CREATE TABLE Student ( Sno CHAR(8) PRIMARY KEY, -- 学号,主键,唯一标识 Sname CHAR(10), -- 姓名 Ssex CHAR(2), -- 性别 Sage INT, -- 年龄 Sdept CHAR(20) -- 系别 );这里最容易忽略的是数据类型的选择逻辑。CHAR(n)是定长,适合学号、课程号这种长度固定的编码;VARCHAR(n)是变长,适合姓名、部门名这类长度不定的文本;SMALLINT比INT省空间,年龄字段用SMALLINT更合理。实验里ALTER TABLE Student ALTER COLUMN Sage SMALLINT就是在做这个优化。数值型里NUMERIC(8,2)用于工资这种需要精确小数位的场景,别用FLOAT,浮点误差在金额计算里是血泪教训。
SC 表是典型的复合主键 + 双外键结构:
CREATE TABLE SC ( Sno CHAR(8), Cno CHAR(4), Score INT, PRIMARY KEY (Sno, Cno), -- 复合主键 FOREIGN KEY (Sno) REFERENCES Student(Sno), -- 外键引用 Student FOREIGN KEY (Cno) REFERENCES Course(Cno) -- 外键引用 Course );选课记录的唯一性由(Sno, Cno)联合主键保证,这意味着同一个学生同一门课只能有一条记录。外键则保证了你不能给一个不存在的学生选课,也不能选一门不存在的课。这两条约束是后面「数据完整性」实验的核心验证点。
2.2 索引:聚簇与非聚簇的选择逻辑
索引实验里出现了四种创建方式,对比着看才能理解区别:
| 索引类型 | 语句示例 | 特点 | 适用场景 |
|---|---|---|---|
| 普通索引 | 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) | 唯一 + 聚簇 | 主键列(通常自动创建) |
最容易踩的坑是:一张表只能有一个聚簇索引,因为数据的物理顺序只有一种。实验里对 SC 表建了(Sno, Cno DESC)的聚簇索引,意味着数据按学号升序、同学生按课程号降序物理排列。如果后面再对 SC 建另一个聚簇索引就会翻车。非聚簇索引则可以有多个,它维护的是独立的索引结构,通过指针回表查数据。
2.3 视图:虚拟表的本质与使用边界
视图在实验里出现了三次,分别是学生基本信息视图、均分视图和选课信息视图。视图的本质是一条被命名的 SELECT 语句,它不存储数据,每次查询时动态执行。
CREATE VIEW IS_Student AS SELECT Sno, Sname, Sage FROM Student WHERE Sdept = 'IS';这个视图的作用是把「信息系学生」这个常用查询条件封装起来,后续直接SELECT * FROM IS_Student就行。均分视图S_G(Sno, Gavg)则展示了视图的另一类用法——在视图上做聚合:
CREATE VIEW S_G(Sno, Gavg) AS SELECT Sno, AVG(Score) FROM SC GROUP BY Sno;梳理下来会发现,视图的核心价值有两个:简化复杂查询(尤其是多表连接),以及做权限隔离(只暴露部分列给特定用户)。但要注意,含聚合函数、GROUP BY、DISTINCT 的视图通常不可更新,这是考试和上机都容易忽略的限制。
3. 数据操作与查询:增删改查的完整复习框架
3.1 插入、修改、删除的约束联动
数据操作实验里,插入语句看起来简单,但每一条都在和约束打交道。比如INSERT INTO Student VALUES ('20100003','刘洋','女',null,null,'1001')这条,Sage 和 Sdept 传了 NULL,能成功是因为建表时这两列没有 NOT NULL 约束。如果 Sname 传 NULL 就会直接报错。
修改操作里有两个典型模式值得记住。一是直接更新:UPDATE Student SET Sage = 22 WHERE Sno = '20100001'。二是带子查询的更新:
UPDATE SC SET Score = Score + 5 WHERE 'CS' = (SELECT Sdept FROM Student WHERE Student.Sno = SC.Sno);这条语句的逻辑是:先通过关联子查询找到每个选课记录对应的学生所在系,如果该系是 CS,就给成绩加 5 分。子查询在这里充当了一个动态的条件过滤器,这是考试里高频出现的写法。
删除操作同样有约束联动的坑。DELETE FROM Student WHERE Sno = '20100022'能执行的前提是 SC 表中没有该学号的选课记录,否则外键约束会阻止删除。实验里用临时表tmpSC来练习删除,就是为了避免直接操作 SC 表时被外键卡住。这个「先复制到临时表再操作」的思路,在实际工作中做危险删除前的备份时同样适用。
3.2 单表查询:条件表达式的完整清单
单表查询实验覆盖了几乎所有 WHERE 子句的写法,整理成一张速查表:
| 查询类型 | 关键词 | 示例 |
|---|---|---|
| 范围查询 | BETWEEN ... AND ... | WHERE Sage BETWEEN 20 AND 23 |
| 集合查询 | IN (...) | WHERE Sdept IN ('IS','MA','CS') |
| 模糊查询 | LIKE | WHERE Sname LIKE '刘%' |
| 空值查询 | IS NULL | WHERE Score IS NULL |
| 多重条件 | AND/OR | WHERE Sdept='CS' AND Sage<20 |
| 排序 | ORDER BY ... ASC/DESC | ORDER BY Sdept, Sage DESC |
模糊查询里%匹配任意长度字符,_匹配单个字符,这个区别考试常考。空值查询必须用IS NULL而不是= NULL,因为 NULL 不等于任何值,包括它自己——这是最容易翻车的一个点。
3.3 分组统计与连接查询的写法对比
分组统计的核心是GROUP BY+ 聚集函数 +HAVING的三件套:
SELECT Cno AS 课程号, COUNT(*) AS 人数, AVG(Score) AS 均分, MAX(Score) AS 最高分 FROM SC GROUP BY Cno HAVING AVG(Score) > 90;这里的关键区分是:WHERE在分组前过滤行,HAVING在分组后过滤组。WHERE里不能直接用聚集函数,HAVING里可以。实验里「统计均分大于 90 的课程」就必须用HAVING,写成WHERE AVG(Score) > 90会直接报错。
连接查询有两种写法,实验里都出现了:
-- 写法一:WHERE 中指定连接条件 SELECT Student.Sno, Sname, Cno, Score FROM Student, SC WHERE Student.Sno = SC.Sno; -- 写法二:FROM 中指定连接条件(JOIN ON) SELECT Student.Sno, Sname, Cno, Score FROM Student JOIN SC ON (Student.Sno = SC.Sno);两种写法结果一样,但 JOIN ON 的写法更清晰,尤其是多表连接时不容易漏掉连接条件。外连接则用LEFT OUTER JOIN,保证左表所有行都出现,右表没有匹配的填 NULL——实验里「查询每个学生信息及其选修课程的情况」就是典型场景,没选课的学生也要出现在结果里。
3.4 嵌套查询与集合查询的适用场景
嵌套查询实验里出现了四种引出方式:IN、比较运算符、带修饰符的比较运算符(ALL)、EXISTS。其中EXISTS的写法最特殊:
SELECT Sname FROM Student WHERE EXISTS ( SELECT * FROM SC WHERE Sno = Student.Sno AND Cno = '1' );EXISTS后面的子查询不返回具体数据,只返回真/假。它的执行逻辑是:对 Student 表的每一行,代入子查询看是否有匹配的 SC 记录。这种「相关子查询」的写法在考试里经常和IN做对比,IN适合子查询结果集小的情况,EXISTS适合外层表小、内层表大的情况。
集合查询的UNION、INTERSECT、EXCEPT分别对应并、交、差。实验里用它们来查询「CS 系学生」和「年龄不大于 19 岁学生」的各种组合。注意UNION会自动去重,如果要保留重复行需要用UNION ALL。
4. 数据完整性与约束:最容易漏掉的五个细节
4.1 易漏点一:主键冲突的报错信息不会看
实验里插入重复学号INSERT INTO Student VALUES('20100001','李斌',...)会报主键冲突错误。很多人看到报错就慌,其实错误信息里明确写了是哪个约束被违反。梳理下来会发现,SQL Server 的报错格式是「Violation of PRIMARY KEY constraint 'PK__Student__...'」,看到PRIMARY KEY就知道是主键重复,看到FOREIGN KEY就知道是外键引用问题,看到CHECK就知道是检查约束不通过。学会读报错信息比背语句更重要。
4.2 易漏点二:CHECK 约束的修改要先删后加
实验里修改 SC 表的成绩约束时,用了两步:
ALTER TABLE SC DROP CONSTRAINT SC_CHECK; ALTER TABLE SC ADD CONSTRAINT SC_CHECK CHECK(Grade >= 0 AND Grade <= 100);不能直接修改 CHECK 约束的定义,必须先删除再重新添加。这个操作在考试里经常以「如何修改已有约束」的形式出现,很多人只记得ALTER TABLE ADD CONSTRAINT,忘了前面还要DROP。
4.3 易漏点三:外键引用自表时的插入顺序
Course 表有一个自引用外键Cpno REFERENCES Course(Cno),表示先修课。这意味着插入数据时必须先插入被引用的课程。实验里先插入了Cno='5'的数据结构,再插入Cno='1'的数据库系统原理(它的 Cpno 是 5),顺序反了就会报外键错误。这个细节在「检查完整性约束」部分经常被忽略,但实际插入数据时一定会遇到。
4.4 易漏点四:DEFAULT 约束只在省略列时生效
Student 表的Stotal SMALLINT DEFAULT 0这个默认值约束,只有在 INSERT 语句中省略 Stotal 列时才会自动填 0。如果显式写了INSERT INTO Student VALUES(..., NULL),那 Stotal 就是 NULL 而不是 0。实验里INSERT INTO Student(Sno,Sname,Ssex,Sclass) VALUES('20100102','张盛','男','1008')这条语句省略了 Sage、Sdept、Stotal,所以 Stotal 自动填 0,Sage 和 Sdept 填 NULL。
4.5 易漏点五:UNIQUE 约束与主键的区别
实验里对 Course 表的 Cname 加了UNIQUE约束,然后尝试插入两门都叫「数据结构」的课程,第二条会报唯一约束冲突。UNIQUE 和 PRIMARY KEY 的区别在于:主键不允许 NULL,UNIQUE 允许一个 NULL 值(SQL Server 的行为);一张表只能有一个主键,但可以有多个 UNIQUE 约束。这个区别在选择题里经常出现。
5. 复习清单与查漏补缺:一份可以照着走的自检流程
复习数据库实验这部分,最怕的是「看一遍都会,一写就错」。我的做法是把整个实验内容拆成一条可执行的自检流程,每次复习时从头走一遍,哪一步卡住了就回去补哪一块。
第一步,关掉实验报告,在白纸上默写 Student、Course、SC 三张表的完整建表语句,包括所有约束。写完后对照实验报告检查:主键写了吗?外键引用对了吗?CHECK 约束的范围对吗?DEFAULT 值设了吗?这一步能暴露 80% 的语法记忆漏洞。
第二步,针对每张表各写一条插入、一条修改、一条删除语句,然后自己判断这条语句会不会违反约束。比如「删除 Student 表中一条有选课记录的学生」会触发外键约束,「插入一条 Score 为 150 的记录」会触发 CHECK 约束。能预判约束是否触发,才算真正理解了完整性。
第三步,把单表查询、分组统计、连接查询、嵌套查询各挑一道实验里的原题,不看答案手写。写完重点检查:WHERE 和 HAVING 有没有用混?IS NULL有没有写成= NULL?连接查询有没有漏掉连接条件导致笛卡尔积?EXISTS的子查询有没有正确关联外层表?
第四步,用一张 A4 纸画出整个实验的知识地图:左边是数据定义(表、约束、索引、视图),右边是数据操作(增删改查),中间用箭头标出依赖关系。比如「外键约束依赖被引用表的主键」「视图依赖基表」「索引依赖表」。画完这张图,整个实验的体系就串起来了。
第五步,把实验里所有报错过的地方单独列一份「翻车清单」。比如主键冲突、外键引用失败、CHECK 约束不通过、= NULL查不出结果、WHERE里用聚集函数报错。每次复习先看这份清单,提醒自己别再踩同样的坑。
提示:复习时优先保证建表和约束部分的正确率,因为后面的查询和更新都建立在这张表结构之上。表建错了,后面全错。
从那以后我每次复习数据库实验,都强制自己先默写建表语句再做题,不翻报告不动键盘。这个习惯帮我避开了很多「看着会、写着错」的坑。希望这份笔记也能帮到你。
本文还有配套的精品资源,点击获取