简介:这份资源是南华大学数据库原理课程的实验报告文档,面向大数据技术等专业学生及数据库初学者,用于完成DBMS认识、SQL查询与数据更新等实验任务。报告围绕SQL Server Management Studio展开,涵盖创建“学生选课200905”与“StuCou200905”数据库、构建学生、课程、选修三张表并定义主码外码与默认值,以及单表查询、多表连接查询、高级SQL查询和数据更新等实验内容,完整呈现了从建库建表到查询操作的实践流程。资源包为1个doc文件,大小5.38MB,结构清晰,便于按实验顺序查阅与对照练习。目前已有375人学习下载。读者可借助其中的实验题目、要求与代码示例,理解表间一对多、多对多关系及实体完整性与参照完整性,掌握SELECT语句在筛选、排序、分组和联接中的用法,为数据库开发、数据分析等方向打下基础。
1. 数据库原理实验报告到底在讲什么:从一份课程作业看懂 SQL 的骨架
很多人第一次听到「数据库原理实验报告」,脑子里浮现的画面大概是:一堆表格、一堆看不懂的英文大写单词、还有同学在群里问「你第三题查出来几行」。它听起来像是一门课的作业,实际上它是一份把数据库核心概念串起来的练习册——从怎么建库、怎么建表,到怎么用 SQL 把想要的数据捞出来。
通俗地说,数据库就像一个大仓库,表是货架,字段是货架上的标签,而 SQL 就是你跟仓库管理员说的话。这份实验报告做的事,就是让你从「认识仓库」开始,一步步学会「怎么跟管理员下指令」。它覆盖了 DBMS 的基本操作、数据库和表的创建、表间关系的定义、单表查询、多表连接查询、嵌套查询和组合查询。搞懂它,你就搞懂了关系型数据库最基础的那套逻辑。
2. 为什么数据库要先讲「关系」:表与表之间的那根线
2.1 三张表怎么就把学生、课程、选课说清楚了
实验里反复出现三张表:学生表、课程表、选修表。学生表存的是「谁」,课程表存的是「有什么课」,选修表存的是「谁选了什么课、考了多少分」。这三张表单独看都很简单,但把它们放在一起,就能回答「计算机系选了数据库原理的学生有哪些」这种复杂问题。
打个比方,学生表像一本花名册,课程表像一张课程清单,选修表像一张签到表。签到表上只写学号和课程号,不写姓名和课程名,因为姓名去花名册查、课程名去课程清单查就行了。这样做的好处是:学生改了名字,只需要改花名册一处;课程改了名称,只需要改课程清单一处。如果签到表上把姓名和课程名都抄一遍,改起来就容易漏、容易错。
这就是关系型数据库的核心思路:数据不重复存,用关联字段把表连起来。学号在学生表里是主码,在选修表里是外码;课程号在课程表里是主码,在选修表里也是外码。主码保证每行数据唯一,外码保证选修表里的学号和课程号一定能在对应的表里找到。
2.2 主码、外码、默认值:三个最容易被跳过但最不能跳过的定义
实验要求里专门提到「为性别和学分属性定义默认值」,还要求「指定主码、外码」。这些不是走形式,它们直接决定了数据能不能正确存进去。
主码就是一张表里能唯一标识一行的字段。学生表用学号做主码,因为学号不会重复;课程表用课程号做主码;选修表用学号加课程号联合做主码,因为一个学生选一门课只应该有一条记录。
外码是「这张表里的某个字段,是另一张表的主码」。选修表里的学号是外码,指向学生表的学号。外码的作用是防止你往选修表里插入一个不存在的学号——数据库会直接拒绝,因为学生表里根本没有这个人。
默认值是在你不填的时候自动填入的值。实验里要求给性别定义默认值,比如不填就默认「男」或「女」;给学分定义默认值,比如不填就默认 4 分。默认值减少了手动输入的工作量,也避免了空值带来的查询麻烦。
注意:主码和外码的定义顺序有讲究。必须先创建被引用的表(学生表、课程表),再创建引用它们的表(选修表),否则外码找不到引用的目标,建表语句会直接报错。
2.3 用 SQL 建表和用图形界面建表,差别在哪
实验里做了两遍几乎一样的事:先用管理工具的图形界面建库建表,再用 SQL 语句建库建表。很多人觉得这是重复劳动,其实这两条路径解决的是不同问题。
图形界面适合初学者理解「表长什么样」——你能看到字段名、数据类型、是否允许为空这些选项,点一点就能改。但图形界面的问题是:换一台电脑、换一个数据库版本,你之前点的那些操作没法原样搬过去。
SQL 语句建表的优势在于可重复、可版本管理、可自动化。你把建表语句存成一个.sql文件,发给任何同学,他在自己的数据库里执行一遍,就能得到一模一样的表结构。实验里要求用 SQL 语句创建StuCou200905数据库和三张表,就是在训练这种「用代码描述结构」的能力。
-- 创建数据库 CREATE DATABASE StuCou200905; -- 切换到该数据库 USE StuCou200905; -- 创建学生表,学号为主码,性别默认值为'男' CREATE TABLE Stu200905 ( 学号 CHAR(10) PRIMARY KEY, 姓名 VARCHAR(20) NOT NULL, 性别 CHAR(2) DEFAULT '男', 出生日期 DATE, 院系名称 VARCHAR(30), 备注 VARCHAR(100) ); -- 创建课程表,课程号为主码,学分默认值为4 CREATE TABLE Cou200905 ( 课程号 CHAR(6) PRIMARY KEY, 课程名 VARCHAR(30) NOT NULL, 先行课 CHAR(6), 学分 INT DEFAULT 4 ); -- 创建选修表,学号+课程号联合主码,分别指向学生表和课程表 CREATE TABLE SC200905 ( 学号 CHAR(10), 课程号 CHAR(6), 分数 INT, PRIMARY KEY (学号, 课程号), FOREIGN KEY (学号) REFERENCES Stu200905(学号), FOREIGN KEY (课程号) REFERENCES Cou200905(课程号) );上面这段代码里,PRIMARY KEY定义主码,FOREIGN KEY ... REFERENCES定义外码,DEFAULT定义默认值,NOT NULL表示不允许为空。参数CHAR(10)表示固定长度 10 个字符,VARCHAR(20)表示最多 20 个字符的可变长度。这些类型选择直接影响存储空间和查询效率,实验里要求「为属性选择合适的数据类型」,就是在练这个判断。
3. 查询才是重头戏:从单表筛选到多表连接的思维跃迁
3.1 单表查询:WHERE 后面那串条件到底怎么写的
实验 2 的前半部分全是单表查询,题目看起来五花八门,但拆开看只有几个套路。
第一个套路是按条件筛行。比如「查询计算机系全体学生的信息」,就是在WHERE后面写院系名称 = '计算机系'。「查询姓李的学生」用的是姓名 LIKE '李%',百分号表示后面可以是任意字符。「查询考试成绩有不及格的学生的学号」用的是分数 < 60。
第二个套路是对结果做计算和排序。比如「查询全体计算机系学生的姓名及其年龄」,年龄不是表里存的字段,而是用当前年份减去出生年份算出来的。实验里用的写法大致是YEAR(GETDATE()) - YEAR(出生日期) AS 年龄。AS是给计算结果起个别名,方便阅读。
第三个套路是分组统计。比如「查询选修了两门以上课程的学生学号与课程数」,这里用到了GROUP BY和HAVING。GROUP BY 学号把同一个学生的选课记录归到一组,COUNT(*)数出一共有几条,HAVING COUNT(*) > 2筛选出选课数大于 2 的组。
-- 查询选修了两门以上课程的学生学号与课程数 SELECT 学号, COUNT(*) AS 选课数 FROM SC200905 GROUP BY 学号 HAVING COUNT(*) > 2; -- 查询选修课程数大于等于2的学生的学号、平均成绩和选课门数 -- 并按平均成绩降序排列 SELECT 学号, AVG(分数) AS 平均成绩, COUNT(*) AS 选课门数 FROM SC200905 GROUP BY 学号 HAVING COUNT(*) >= 2 ORDER BY 平均成绩 DESC;这里的关键区别是:WHERE在分组之前筛选行,HAVING在分组之后筛选组。ORDER BY放在最后,DESC表示降序。很多人第一次写的时候会把HAVING写成WHERE,结果数据库直接报错,因为WHERE不认识COUNT(*)这种聚合函数。
3.2 多表连接:为什么查着查着就查出了重复行
多表查询是实验 2 后半部分和实验 3 的重点。最典型的题目是「查询学生的学号、姓名、选修课程的名称和成绩」。学号和姓名在学生表,课程名在课程表,成绩在选修表——一条查询要同时用到三张表。
连接的基本写法是在FROM后面把两张表都写上,然后在WHERE里写连接条件。比如学生表和选修表通过学号连接:
-- 查询学生的学号、姓名、选修课程的名称和成绩 SELECT S.学号, S.姓名, C.课程名, SC.分数 FROM Stu200905 S JOIN SC200905 SC ON S.学号 = SC.学号 JOIN Cou200905 C ON SC.课程号 = C.课程号;这里用了JOIN ... ON的写法,比在WHERE里写连接条件更清晰。S、SC、C是表的别名,避免字段名重复时产生歧义。
多表连接最容易翻车的地方是连接条件写漏或写错。如果你只写了FROM Stu200905, SC200905但忘了写WHERE S.学号 = SC.学号,数据库会把两张表的每一行都两两组合一遍,结果行数等于两张表行数的乘积。这个错误叫笛卡尔积,数据量小的时候你还能忍,数据量一大查询直接卡死。
另一个容易混的点是内连接和外连接的区别。内连接只返回两张表都能匹配上的行;左外连接返回左表所有行,右表匹配不上的地方填空值。实验要求里专门提到「比较内连接、外连接的结果」,就是因为这个区别在实际查数据时非常关键。比如「查询所有学生的信息和他们的选课情况」,如果某个学生一门课都没选,内连接会把他漏掉,左外连接才能把他保留下来。
3.3 嵌套查询和组合查询:把一条查询的结果当成另一条查询的条件
实验 3 讲的是嵌套查询和组合查询,这是 SQL 从「会写」到「写得巧」的分水岭。
嵌套查询的思路是:先查出一个结果集,再用这个结果集去筛选另一张表。比如「查询没有选修数据库原理课程的学生信息」,可以先查出选修了数据库原理的学生学号,然后用NOT IN排除掉这些人。
-- 查询没有选修数据库原理课程的学生信息 SELECT * FROM Stu200905 WHERE 学号 NOT IN ( SELECT SC.学号 FROM SC200905 SC JOIN Cou200905 C ON SC.课程号 = C.课程号 WHERE C.课程名 = '数据库原理' );组合查询用的是UNION、INTERSECT、EXCEPT这三个集合运算符。UNION把两个查询结果合并去重,INTERSECT取两个结果的交集,EXCEPT取差集。实验里要求「用 UNION 组合查询与 IN 条件查询两种方法实现同一道题」,就是在训练你用不同思路解决同一个问题。
提示:
UNION会自动去重,如果不想去重就用UNION ALL。INTERSECT和EXCEPT在不同数据库里的支持程度不一样,写之前最好确认一下当前环境是否支持。
4. 常见误区:这几个概念一混,查询结果就全错了
4.1 主码和外码:都是码,到底谁约束谁
易混点:主码和外码都叫「码」,初学者容易觉得它们是一回事。
为什么混:两个概念都涉及「唯一标识」和「表间关系」,名字又只差一个字。
怎么区分:主码是「我这行我说了算」——它唯一标识本表的一行,不允许重复、不允许为空。外码是「我指向别人」——它的值必须能在另一张表的主码里找到,或者为空。一张表只能有一个主码,但可以有多个外码。学生表的学号是主码,选修表的学号是外码,选修表的学号加课程号是联合主码。
4.2 WHERE 和 HAVING:都是筛选,位置不同结果不同
易混点:两个都可以写条件,看起来功能差不多。
为什么混:初学时写的查询简单,用 WHERE 能解决大部分问题,遇到 HAVING 就觉得是另一种写法的 WHERE。
怎么区分:WHERE 在分组之前筛选行,不能使用聚合函数(COUNT、SUM、AVG 等)。HAVING 在分组之后筛选组,必须和 GROUP BY 配合使用,可以使用聚合函数。如果你要筛「分数大于 80 的记录」,用 WHERE;如果你要筛「平均分大于 80 的学生」,用 HAVING。
4.3 内连接和外连接:差一个 LEFT,差出一批数据
易混点:JOIN和LEFT JOIN看起来只差一个单词,结果集却可能差很多行。
为什么混:数据量小的时候,两种连接的结果可能一模一样,因为每行都能匹配上。
怎么区分:内连接只保留两张表都能匹配的行。左外连接保留左表所有行,右表匹配不上的字段填 NULL。判断用哪个的标准是:左表的数据是否允许丢失。如果「查询所有学生的选课情况」,学生是左表,即使某个学生没选课也要出现在结果里,就必须用左外连接。
4.4 UNION 和 UNION ALL:去重和不去重,性能差一截
易混点:两个都是合并结果集,写哪个都行。
为什么混:小数据量下结果看起来一样,因为本来就没有重复行。
怎么区分:UNION会去掉重复行,UNION ALL保留所有行。去重需要排序和比较,所以UNION比UNION ALL慢。如果你确定两个结果集没有重复,或者你就是要保留重复,用UNION ALL更高效。
4.5 空值 NULL:不是 0,也不是空字符串
易混点:NULL 看起来就是「什么都没有」,那判断的时候写= NULL应该可以吧。
为什么混:直觉上「等于空」是一个合理的判断。
怎么区分:NULL 在 SQL 里表示「未知」,它不等于任何值,也不等于另一个 NULL。判断 NULL 必须用IS NULL或IS NOT NULL,写= NULL永远返回假。另外,NULL 参与算术运算结果还是 NULL,参与聚合函数时会被跳过。实验里定义字段时决定「是否允许为空」,就是在控制这个字段能不能出现 NULL。
5. 什么时候该翻出这份实验报告:一个过来人的使用边界
这份实验报告最直接的用途,是帮你建立关系型数据库的第一层认知框架。如果你正在学数据库原理课,或者刚开始接触 SQL,它是一份很好的练习路线图:先认识 DBMS,再建库建表,然后从单表查询练到多表连接,最后用嵌套查询和组合查询收尾。这个顺序不是随便排的,每一步都在为下一步打基础。
但也要说清楚它不适合什么场景。这份报告里的 SQL 是教学用的标准写法,实际工作中你会遇到更复杂的性能问题、更严格的权限管理、更大规模的数据量。实验里查的是几十行数据,生产环境里查的是几百万行,同样的 SQL 写法可能需要加索引、改连接方式、甚至换查询策略。另外,实验用的是 SQL Server 的语法,换到 MySQL 或 PostgreSQL 时,日期函数、字符串函数、分页写法都会有差异,不能直接照搬。
如果你只是想快速搞懂「数据库是什么」「SQL 能干什么」,这份报告的前两个实验就够了。如果你要准备面试或者做实际项目,实验 2 和实验 3 里的多表连接、嵌套查询、组合查询是必须练熟的部分,因为它们是 SQL 面试题里出现频率最高的题型。
我自己刚开始学的时候,总觉得建表语句写一遍就行了,反正图形界面也能建。后来有一次帮同学看一个查询问题,他把连接条件写在了 WHERE 里但漏了一个,结果查出来的数据多了一倍。我让他把 SQL 改成JOIN ... ON的写法,问题一眼就看出来了。从那以后我每次写多表查询,都强制自己先把连接条件单独写出来,确认每张表都连上了,再往上面加筛选条件。这个习惯帮我省了很多排查时间。
希望这份实验报告能帮你把数据库的底子打扎实,后面遇到更复杂的查询时,你知道该从哪里拆、从哪里查。
本文还有配套的精品资源,点击获取