简介:这份资源是太原理工大学软件工程专业「数据库概论」课程的实验报告文档,面向正在学习数据库系统原理、需要完成SQL上机实验的本科生与自学者。报告以Microsoft SQL Server 2016为实验平台,围绕交互式SQL语句的使用展开,涵盖数据定义、索引创建、视图创建与数据操作四大模块,具体包括用CREATE TABLE建表、ALTER TABLE修改结构、DROP TABLE删除表,以及唯一索引、聚簇索引的建立和IS_Student视图的编写,并配有Student、Course、Sc等表的完整SQL示例与插入、更新语句。资源包内含1个docx文件,大小约1.69MB,结构完整、代码可直接参考。目前已有311人学习下载,适合需要对照实验步骤、梳理SQL语法要点或撰写同类实验报告的同学借鉴使用。
1. 数据库概论实验的知识地图:从建表到查询的完整链路
数据库概论的实验课,很多人以为就是敲几条 SQL 语句交差,但真正梳理下来会发现,它其实是一条从「定义结构」到「约束数据」再到「操控数据」的完整链路。整份实验报告围绕三个实验展开:交互式 SQL 语句的使用、数据完整性、用户鉴别与数据控制。前两个是核心,第三个是延伸。这条链路可以拆成四层:第一层是数据定义,建表、改表、删表、建索引、建视图;第二层是数据操作,增删改查四件套;第三层是数据完整性,主键、外键、CHECK、DEFAULT、触发器;第四层是数据控制,用户权限与鉴别。每一层都依赖上一层的正确执行,比如外键约束要求被引用的主键先存在,视图查询依赖基表有数据。适合正在系统学数据库、准备实验考试或期末复习的人对照查漏。下面按模块逐层拆开。
2. 数据定义与数据操作:建表、索引、视图与增删改查的复习重点
2.1 基本表的创建、修改与删除
建表是整个实验的起点。实验中使用CREATE TABLE定义了 Student、Course、SC、Employee 四张表,覆盖了三种典型场景:单主键表、复合主键表、带外键的关联表。
-- 单主键表:学号为主键 CREATE TABLE Student( Sno CHAR(8) PRIMARY KEY, Sname CHAR(10), Ssex CHAR(2), Sage INT, Sdept CHAR(20) ); -- 复合主键 + 双外键:选课表 CREATE TABLE SC( Sno CHAR(8), Cno CHAR(4), Score INT, PRIMARY KEY(Sno, Cno), FOREIGN KEY(Sno) REFERENCES Student(Sno), FOREIGN KEY(Cno) REFERENCES Course(Cno) );这里的关键点有三个。第一,CHAR和VARCHAR的区别:CHAR是定长,不足部分补空格;VARCHAR是变长,按实际长度存储。实验中 Student 表的 Sname 用CHAR(10),Employee 表的姓名用VARCHAR(8),两种都能用,但变长字段更省空间。第二,复合主键的写法是PRIMARY KEY(Sno, Cno),不是在两列后面各写一个 PRIMARY KEY。第三,外键的引用顺序:必须先创建被引用的表(Student、Course),再创建引用表(SC),否则会报错。
修改表结构用ALTER TABLE,实验中涉及三种操作:加列(ADD Sclass char(4))、改列类型(ALTER COLUMN Sage smallint)、加约束(ADD UNIQUE(Cname))。删除表用DROP TABLE,注意这个操作不可逆,表结构和数据一起消失。
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) | 主键自动有唯一索引 |
聚簇索引和普通索引的区别是考试高频点:聚簇索引决定表中数据的物理排列顺序,一张表只能有一个;普通索引只建立指向数据的指针,可以有多个。实验中iSnoCno用了DESC指定降序,说明索引可以控制排序方向。
视图是一个虚拟表,不存储数据,只保存查询定义。实验中创建了IS_Student视图,筛选出 IS 系的学生:
CREATE VIEW IS_Student AS SELECT Sno, Sname, Sage FROM Student WHERE Sdept = 'IS';视图的价值在于简化复杂查询和限制数据访问。查询视图和查询表语法一样,但视图不占物理空间,每次查询时动态生成结果集。
2.3 数据插入、修改与删除
插入数据用INSERT INTO,实验中覆盖了三种方式:单行插入、多行插入(通过INSERT INTO ... SELECT从其他表复制)、省略部分列插入。多行插入的典型写法:
-- 从 Student 表复制 CS 系学生到 cs_Student 表 INSERT INTO cs_Student SELECT Sno, Sname, Sage FROM Student WHERE Sdept = 'CS';修改数据用UPDATE ... SET ... WHERE ...。实验中有一个容易翻车的操作:UPDATE Student SET Sage = Sage + 1,没有 WHERE 条件,所有行都受影响。另一个典型是带子查询的更新:
-- 将 CS 系全体学生成绩加 5 分 UPDATE Sc SET Score = Score + 5 WHERE 'CS' = (SELECT Sdept FROM Student WHERE Student.Sno = Sc.Sno);删除数据用DELETE FROM ... WHERE ...。实验中特别演示了用SELECT INTO创建临时表tmpSC来练习删除操作,这样不会影响原始数据。DELETE FROM tmpSC不带 WHERE 会清空全表,但表结构还在,这和DROP TABLE有本质区别。
3. 数据查询进阶:单表、分组、连接与嵌套查询的要点梳理
3.1 单表查询的条件与排序
单表查询是查询的基础,实验覆盖了十几种条件写法。核心语法结构是SELECT ... FROM ... WHERE ... ORDER BY ...。几个高频考点:
范围查询用BETWEEN ... AND ...,注意边界包含。集合查询用IN,比如WHERE Sdept IN ('IS', 'MA', 'CS')。模糊查询用LIKE,%匹配任意多个字符,_匹配一个字符。空值判断必须用IS NULL,不能用= NULL,这是最常见的易错点之一。
排序用ORDER BY,默认升序(ASC),降序要写DESC。多列排序时,先按第一列排,第一列相同再按第二列排:
-- 按系号升序,同系内按年龄降序 SELECT * FROM Student ORDER BY Sdept ASC, Sage DESC;去重用DISTINCT,比如SELECT DISTINCT Sno FROM Sc查询选修了课程的学生学号。不加 DISTINCT 会返回所有选课记录中的学号,有重复。
3.2 分组统计与聚集函数
聚集函数是分组统计的核心工具,常用的有五个:COUNT、SUM、AVG、MAX、MIN。实验中的典型用法:
-- 统计各门课程的选课人数、均分和最高分 SELECT Cno AS 课程号, COUNT(*) AS 人数, AVG(Score) AS 均分, MAX(Score) AS 最高分 FROM Sc GROUP BY Cno HAVING AVG(Score) > 90;这里有两个关键区别必须搞清楚。第一,WHERE和HAVING的区别:WHERE在分组前过滤行,HAVING在分组后过滤组。WHERE中不能用聚集函数,HAVING中可以。第二,COUNT(*)和COUNT(DISTINCT Sno)的区别:前者统计所有行数,后者统计不重复的学号数。实验中查询选修了课程的学生人数就用了COUNT(DISTINCT Sno),因为一个学生可能选多门课。
分组时,SELECT后面只能出现分组列和聚集函数,不能出现其他未分组的列。这是 SQL 标准的要求,也是考试常考的判断题。
3.3 连接查询与嵌套查询
连接查询是多个表联合查询的主要方式。实验中涉及三种写法:
-- 写法一:WHERE 中指定连接条件 SELECT Student.Sno, Sname, Cno, Score FROM Student, SC WHERE Student.Sno = SC.Sno; -- 写法二:JOIN ... ON SELECT Student.Sno, Sname, Cno, Score FROM Student JOIN SC ON (Student.Sno = SC.Sno); -- 写法三:外连接(保留左表所有行) SELECT Student.Sno, Sname, Cno, Score FROM Student LEFT OUTER JOIN SC ON (Student.Sno = SC.Sno);内连接只返回两表都匹配的行,外连接会保留一侧表中不匹配的行(缺失部分填 NULL)。实验中查询「每个学生信息及其选修课程的情况」用的就是左外连接,这样没选课的学生也会出现在结果中。
嵌套查询是把一个查询的结果作为另一个查询的条件。IN引出的子查询返回一个集合,EXISTS引出的子查询返回真或假。EXISTS的典型用法:
-- 查询选修了 1 号课程的学生姓名 SELECT Sname FROM Student WHERE EXISTS ( SELECT * FROM SC WHERE Sno = Student.Sno AND Cno = '1' );EXISTS和IN的区别在于:IN先执行子查询再比较值,EXISTS对外表的每一行执行子查询判断是否存在。数据量大时EXISTS通常更快。
集合查询用UNION(并)、INTERSECT(交)、EXCEPT(差),要求两个查询的列数和数据类型一致。
4. 数据完整性与约束:主键、外键、CHECK 与默认值的易错点
4.1 五类约束的创建与验证
数据完整性靠约束来保证。实验中涉及五类约束:
| 约束类型 | 关键字 | 作用 | 示例 |
|---|---|---|---|
| 主键约束 | PRIMARY KEY | 唯一标识,非空 | Sno CHAR(8) PRIMARY KEY |
| 外键约束 | FOREIGN KEY | 引用另一表的主键 | FOREIGN KEY(Sno) REFERENCES Student(Sno) |
| 唯一约束 | UNIQUE | 列值不可重复 | ALTER TABLE Course ADD UNIQUE(Cname) |
| 检查约束 | CHECK | 限定取值范围 | CHECK(Ssex IN ('男','女')) |
| 默认值约束 | DEFAULT | 未填时自动赋值 | Stotal SMALLINT DEFAULT 0 |
命名约束是一个好习惯。实验中CONSTRAINT PK_Course PRIMARY KEY、CONSTRAINT SC_CHECK CHECK(...)、CONSTRAINT FK_SC FOREIGN KEY(...)都用了命名,方便后续用ALTER TABLE ... DROP CONSTRAINT 约束名来修改或删除。
修改约束的典型操作是先删后加:
-- 修改 SC 表的成绩检查约束 ALTER TABLE SC DROP CONSTRAINT SC_CHECK; ALTER TABLE SC ADD CONSTRAINT SC_CHECK CHECK(Grade >= 0 AND Grade <= 100);4.2 完整性约束的验证方法
实验中最有价值的部分是通过插入非法数据来验证约束是否生效。几个典型场景:
插入重复主键会报错,比如INSERT INTO Student VALUES('20100001', ...)在 Sno 已存在时被拒绝。插入违反外键的数据也会报错,比如 SC 表中插入一个 Student 表里不存在的学号。插入违反 CHECK 约束的数据同样被拒绝,比如性别填了「男」「女」以外的值,或者成绩超出 0 到 100 的范围。
默认值约束的验证方式是插入时省略该列,观察是否自动填入默认值。实验中INSERT INTO Student(Sno, Sname, Ssex, Sclass) VALUES('20100102', '张盛', '男', '1008')省略了 Sage 和 Stotal,Stotal 会自动填 0。
5. 最容易翻车的五个点:从约束冲突到查询空值的踩坑记录
5.1 易漏点一:外键引用顺序与级联操作
易漏点:建表时先建了 SC 表再建 Student 表,导致外键引用失败。
为什么漏:很多人按实验报告的书写顺序敲代码,没注意表之间的依赖关系。SC 表的外键引用了 Student 和 Course 的主键,被引用的表必须先存在。
怎么补:建表顺序遵循「先主表后从表」原则。如果已经建错了,先DROP TABLE SC再重新按正确顺序创建。另外,删除表时顺序相反,先删从表再删主表。
5.2 易漏点二:空值判断用 = NULL 而不是 IS NULL
易漏点:写WHERE Score = NULL查不到任何结果。
为什么漏:SQL 中 NULL 表示未知,任何值与 NULL 比较都返回未知(UNKNOWN),不是真也不是假。= NULL永远不成立。
怎么补:判断空值必须用IS NULL或IS NOT NULL。同理,WHERE Score <> NULL也查不到东西,要用IS NOT NULL。
5.3 易漏点三:GROUP BY 后 SELECT 出现非分组列
易漏点:SELECT Sno, Cno, AVG(Score) FROM Sc GROUP BY Sno中 Cno 没有出现在 GROUP BY 中。
为什么漏:写查询时习惯性把想要的列都列出来,忽略了分组后每组的非分组列可能有多个值,数据库不知道该显示哪一个。
怎么补:GROUP BY 后 SELECT 的列只能是分组列和聚集函数。如果确实需要显示其他列,要么加入 GROUP BY,要么用子查询或连接来实现。
5.4 易漏点四:DELETE 和 DROP 混用
易漏点:想清空表数据但用了DROP TABLE,把表结构也删了。
为什么漏:DELETE FROM 表名删除数据但保留表结构,DROP TABLE 表名连表结构一起删除。两者只差一个词,效果完全不同。
怎么补:只想清数据用 DELETE,想彻底删表用 DROP。如果只是想临时操作,可以用SELECT INTO创建临时表来练习,避免影响原始数据。
5.5 易漏点五:连接查询中漏写连接条件导致笛卡尔积
易漏点:SELECT * FROM Student, SC没有 WHERE 连接条件,返回了 Student 行数乘以 SC 行数的结果。
为什么漏:多表查询时忘记写连接条件,或者 JOIN 后面漏了 ON 子句。
怎么补:多表查询必须指定连接条件。用 WHERE 写法时检查是否有表1.列 = 表2.列,用 JOIN 写法时检查是否有ON子句。执行前先估算结果行数,如果远大于预期,大概率是漏了连接条件。
6. 复习清单与查漏补缺:一份可以照着走的自检流程
复习数据库概论实验,最有效的方式不是重读实验报告,而是按一条固定的自检流程走一遍。下面这份清单按操作类型分组,每一项都可以直接在 SSMS 里执行验证。
建表与约束自检:创建 Student、Course、SC 三张表,确保主键、外键、CHECK、DEFAULT 都设置正确。然后故意插入一条违反主键的数据、一条违反外键的数据、一条违反 CHECK 的数据,确认数据库都报错。这一步能同时验证约束是否生效和报错信息是否理解。
查询自检:按以下顺序各写一条 SQL 并执行——单表条件查询、模糊查询、空值查询、分组统计带 HAVING、两表连接查询、嵌套查询用 EXISTS、集合查询用 UNION。每条查询写完后,先自己预判结果行数,再执行对比。预判和实际不一致的地方就是需要重点复习的地方。
易错点自检:把上面五个易漏点逐一过一遍。重点确认三件事:空值判断用的是 IS NULL 不是 = NULL;GROUP BY 后 SELECT 没有多余的非分组列;多表查询没有漏连接条件。
修改与删除自检:用 SELECT INTO 创建临时表,在临时表上练习 UPDATE 和 DELETE,确认 WHERE 条件写对。特别注意不带 WHERE 的 UPDATE 和 DELETE 会影响全表,执行前先用 SELECT 确认影响范围。
-- 执行 UPDATE 或 DELETE 前,先用 SELECT 确认影响范围 SELECT * FROM Sc WHERE Sno = '20100001' AND Cno = '1'; -- 确认无误后再执行删除 DELETE FROM Sc WHERE Sno = '20100001' AND Cno = '1';梳理下来会发现,数据库实验的难点不在语法本身,而在细节的准确性。一个=和IS的区别、一个 WHERE 条件的遗漏、一个建表顺序的错误,都会导致结果完全偏离预期。我自己的习惯是每次执行 UPDATE 或 DELETE 之前,强制先用 SELECT 把 WHERE 条件跑一遍,确认影响的行数和预期一致再执行。这个习惯帮我避开了好几次全表更新的翻车。希望这份梳理能帮到你。
本文还有配套的精品资源,点击获取