简介本资源是太原理工大学软件工程专业《数据库概论》课程配套的完整实验报告面向高校数据库初学者、软件工程专业学生及SQL入门实践者聚焦数据库核心操作能力训练。报告覆盖SQL Server 2016环境下数据定义CREATE/ALTER/DROP TABLE、索引创建唯一索引、聚簇索引、视图构建如IS_Student系别筛选视图及数据增删改查全流程含大量可直接复现的语句示例与关键注意事项助力夯实数据库管理与SQL编程基础。资源为单文件docx文档大小1.69MB结构清晰、排版规范含实验目的、平台配置、分步操作记录及结果截图说明便于对照学习与课堂复盘。已有312人学习下载适合课程复习、实验预习、SQL语法速查及数据库原理实操巩固。1. 数据库不是“存东西的U盘”而是带规则的智能管家为什么软件工程学生必须亲手敲一遍SQL你有没有试过把几百个Excel表格堆在电脑里找一个学生三年前某门课的成绩翻了二十分钟还没找到或者改了一个名字结果在五个表里漏改了一处导致成绩单和花名册对不上——这恰恰是没用数据库的“原始状态”。而数据库不是冷冰冰的数据仓库它更像一位训练有素的办公室主管它不光记事还主动守规矩——谁可以看、谁不能改、姓名不能为空、学号不能重复、成绩必须在0到100之间……这些“规矩”就是数据库的数据完整性而指挥这位主管干活的语言就是SQL结构化查询语言。太原理工大学软件工程专业的这份《数据库概论》实验报告表面是一份学生交的作业内核却是一套经过千锤百炼的“数据库上岗实操手册”从建一张表开始到给它加锁、设岗、定流程、查错、回溯全程用真实SQL Server环境手敲命令。它不讲虚的理论只解决一个现实问题当你的软件系统将来要管几千名学生、上百门课、几万条成绩时怎么让数据不乱、不错、不丢、不被误改这份报告里的每一条CREATE TABLE、每一个CHECK约束、每一次UPDATE失败的报错提示都是在帮你提前踩坑——不是在纸上谈兵是在数据库的“真实战场”上亲手把“数据会自己守规矩”这件事变成肌肉记忆。2. SQL不是“写作文”而是给数据库下指令从建表到查数每一步都在定义数据世界的运行规则2.1 建表不是画格子而是立宪法字段、主键、约束共同构成数据的“身份契约”建一张表远不止是列几个名字那么简单。它是在为未来所有数据订立一份“身份契约”。比如实验中创建的Student表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 );这段代码里每一行都在划清边界Sno CHAR(8) PRIMARY KEY学号是这张表的“身份证号”全表唯一且不能为空——这是主键约束确保每个学生有且只有一个确定身份Sname CHAR(8) NOT NULL姓名不能为空——这是非空约束NOT NULL防止出现“无名氏”记录Ssex CHAR(2) CHECK(Ssex IN (男,女))性别只能填“男”或“女”——这是检查约束CHECK像一道过滤网把“未知”“其他”“1/0”等非法值直接挡在外面Stotal SMALLINT DEFAULT 0总分字段如果没有手动填系统自动填0——这是默认值DEFAULT避免因遗漏导致该字段为NULL而影响后续统计。提示这些约束不是可选项而是数据库的“安全气囊”。没有它们数据就像没装护栏的阳台——表面能站人但一次手滑就可能掉下去。实验中故意插入重复学号(20100001,李斌,男,20,CS,1001,0)SQL Server立刻报错“违反了PRIMARY KEY约束”这就是气囊弹出的瞬间。2.2 插入不是“倒豆子”而是“过安检”数据进库前必须通过类型、长度、逻辑三重校验往表里插数据看起来只是INSERT INTO ... VALUES (...)但背后是数据库在高速执行三重安检-- ✅ 合法插入完全符合表定义 INSERT INTO Student VALUES(20100001,李勇,男,20,CS,1001,0); -- ❌ 非法插入违反CHECK约束性别只能是男或女 INSERT INTO Student VALUES(20100002,刘晨,M,19,CS,1001,0); -- 报错违反了 CHECK 约束 CK__Student__Ssex__...。 -- ❌ 非法插入违反主键约束学号重复 INSERT INTO Student VALUES(20100001,张伟,男,21,IS,1002,0); -- 报错违反了 PRIMARY KEY 约束 PK__Student__...。 -- ❌ 非法插入字段数不匹配少填了Stotal INSERT INTO Student VALUES(20100003,刘洋,女,null,null,1001); -- 报错列名或值的数量与表定义不匹配。这个过程就是数据完整性控制的第一道防线。它不像Excel那样“先让你输进去回头再人工核对”而是“卡在门口不合规矩一步不放行”。实验中反复练习插入、观察报错目的就是让你形成条件反射看到INSERT第一反应不是“我输对了吗”而是“数据库允许我这么输吗”。2.3 查询不是“翻记录”而是“发指令”SELECT 的每个关键词都在精确调度数据库的计算引擎很多人以为SELECT * FROM Student就是“把学生表全拉出来”其实这只是最粗放的调用。真正的SQL查询是一套精密的“数据调度指令集”。实验报告里大量出现的语法正是教你怎么精准下指令目标列控制选什么SELECT Sno, Sname, Sage FROM Student—— 只取三个字段减少网络传输和内存占用SELECT Sname, 2004-Sage AS YearofBirth, LOWER(Sdept) AS dept—— 计算出生年份、统一转小写在查询层完成数据加工而非靠程序代码处理。结果去重去什么SELECT Sno FROM Sc返回所有选课记录的学号含重复SELECT DISTINCT Sno FROM Sc则只返回“选过课”的不同学号——这是业务语义的精准表达“有多少学生选了课”不是“有多少条选课记录”。条件筛选筛什么WHERE Sage BETWEEN 20 AND 23比WHERE Sage 20 AND Sage 23更简洁、可读性更强WHERE Sname LIKE 刘%是模糊匹配“刘晨”“刘洋”“刘敏”全中但WHERE Sname 刘晨只命中一个——模糊查询是业务搜索的刚需不是偷懒。排序与分组怎么组织ORDER BY Sdept, Sage DESC让结果先按系别升序排同系内再按年龄降序——这是报表生成的标准格式GROUP BY Cno HAVING AVG(Score) 90先按课程分组再筛出“平均分超90”的课程——HAVING 是对分组后的结果做条件WHERE 是对原始行做条件混用必翻车。注意这些不是炫技。当你开发一个学生成绩分析后台时前端点一下“按系别查看高分课程”后端SQL就必须写出GROUP BY HAVING点一下“搜姓刘的学生”SQL就必须用LIKE。不会写功能就做不出来。2.4 连接不是“拼表格”而是“搭关系桥”JOIN 的本质是让分散的数据自动认亲现实世界的数据从来不是一张大表。学生信息在Student表课程信息在Course表成绩在Sc表——它们靠外键如Sc.Sno引用Student.Sno建立血缘关系。JOIN的作用就是让数据库根据这些“血缘线索”自动把相关数据拼成一张逻辑视图。实验中对比了两种写法-- 旧式写法隐式连接在WHERE中写条件 SELECT Student.Sno, Sname, Cname, Score FROM Student, Sc, Course WHERE Student.Sno Sc.Sno AND Sc.Cno Course.Cno; -- 新式写法显式JOIN语义清晰 SELECT s.Sno, s.Sname, c.Cname, sc.Score FROM Student s JOIN Sc sc ON s.Sno sc.Sno JOIN Course c ON sc.Cno c.Cno;表面看只是写法差异实则关乎可维护性与健壮性隐式写法容易漏写连接条件一漏就是笛卡尔积比如1000学生 × 100课程 10万行垃圾数据轻则卡死重则拖垮服务器显式JOIN把“连接逻辑”和“筛选逻辑”彻底分开ON专管“谁跟谁连”WHERE专管“连完后筛谁”逻辑一目了然改需求时不易出错。更关键的是外连接LEFT JOINSELECT s.Sno, s.Sname, sc.Score FROM Student s LEFT JOIN Sc sc ON s.Sno sc.Sno这条语句确保“所有学生都出现”哪怕他一条课都没选此时sc.Score为NULL。这是做“应到/实到统计”“未选课学生名单”的核心操作——没有LEFT JOIN那些“安静的学生”就会在结果里神秘消失。2.5 视图不是“截图”而是“活接口”用虚拟表封装复杂逻辑让调用者变轻松视图View常被误解为“保存的SELECT语句”但它真正的价值是把复杂的、多表关联的、带计算的查询逻辑封装成一个简单的、可复用的“虚拟表”。实验中创建了两个典型视图-- 视图1学生基本信息视图屏蔽敏感字段简化常用查询 CREATE VIEW Student_VIEW(学号,姓名,性别,年龄,系,班级) AS SELECT Sno,Sname,Ssex,Sage,Sdept,Sclass FROM Student; -- 视图2学生均分视图封装聚合计算业务方无需懂GROUP BY CREATE VIEW S_G(Sno,Gavg) AS SELECT Sno, AVG(Score) FROM SC GROUP BY Sno;使用时业务人员只需SELECT * FROM Student_VIEW WHERE 系 CS; -- 像查普通表一样简单 SELECT 姓名, Gavg FROM Student_VIEW v JOIN S_G g ON v.学号 g.Sno; -- 均分已算好直接拿来用这相当于把“如何安全地查学生”“如何正确算均分”这两套专业逻辑打包成标准化服务接口。前端工程师不用再背JOIN规则测试同学不用再担心漏写GROUP BY连产品经理看数据都能直接用中文字段名——视图是数据库给协作团队发的“降维武器”。3. 完整性不是“加个锁”而是四层防御体系从约束到触发器数据库如何像交警一样管住数据3.1 四层防御为什么单靠程序员写代码永远防不住数据失真想象一个交通路口如果只靠司机自觉应用层校验红灯亮了还抢行事故必然发生数据库的完整性控制就是在这里部署红绿灯约束、电子警察触发器、道路标线默认值/非空、以及交通指挥中心事务。实验报告中“数据完整性”实验完整演示了这四层如何协同工作防御层级实现方式实验中的例子失效后果第一层域完整性数据类型、CHECK、DEFAULT、NOT NULLSsex CHAR(2) CHECK(Ssex IN (男,女))性别字段存入X、1、未知第二层实体完整性PRIMARY KEY、UNIQUESno CHAR(8) PRIMARY KEY同一学号出现两条学生记录第三层参照完整性FOREIGN KEYFOREIGN KEY (Sno) REFERENCES Student(Sno)成绩表里出现不存在的学生学号第四层用户自定义完整性触发器Trigger、存储过程实验虽未展开但提到了机制业务规则如“退课后学分需重算”无法自动执行提示这四层是由数据库引擎强制执行的不依赖任何应用程序。即使黑客绕过你的Web系统直接连上数据库执行INSERT这些规则依然生效。这是数据可信的底线。3.2 约束不是摆设而是会“咬人”的守门员从实验报错中读懂每一条错误信息实验中反复让你“执行下面的语句观察能否运行解释为什么”就是在训练你读懂数据库的“咬人警告”。例如-- ❌ 尝试插入重复主键 INSERT INTO Student VALUES(20100001,李斌,男,20,CS,1001,0); -- 报错消息 2627级别 14状态 1第 1 行: 违反了 PRIMARY KEY 约束... -- → 解读主键已存在拒绝插入。这是实体完整性在起作用。 -- ❌ 尝试插入空外键 INSERT INTO SC VALUES(20100001,NULL,78); -- 报错消息 515级别 16状态 2第 1 行: 无法将值 NULL 插入列 Cno... -- → 解读Cno 字段定义为 CHAR(4) 且无 NULL 声明属于非空约束失效。 -- ❌ 尝试插入超范围成绩 INSERT INTO SC VALUES(20100001,1,105); -- 报错消息 547级别 16状态 0第 1 行: 违反了 CHECK 约束 SC_CHECK... -- → 解读CHECK(Grade 0 AND Grade100) 被触发成绩必须在0-100间。这些报错信息里的消息编号如2627、515、547和约束名如PK__Student__...就是数据库给你开的“诊断书”。熟练掌握它们比背一百条SQL语法更能提升排错效率——因为你知道是哪一层防线被突破了。3.3 修改约束不是“改配置”而是动手术ALTER TABLE 的风险与必要性生产环境中需求永远在变。今天只要求“成绩是整数”明天可能要支持“95.5分”今天“系别是固定字符串”明天要对接新院系编码。这时就得用ALTER TABLE给表“动手术”。实验中展示了关键操作-- ✅ 安全添加约束表中现有数据必须全部满足新规则 ALTER TABLE Course ADD UNIQUE(Cname); -- 要求所有课程名不能重复 -- ✅ 修改已有约束先删后建避免冲突 ALTER TABLE SC DROP CONSTRAINT SC_CHECK; ALTER TABLE SC ADD CONSTRAINT SC_CHECK CHECK(Grade 0 AND Grade100); -- ⚠️ 危险操作修改列类型可能丢失数据 ALTER TABLE Student ALTER COLUMN Sage SMALLINT; -- 原为 INT改为更小的 SMALLINT -- 如果原数据有 Sage32768超出SMALLINT范围此命令会失败注意ALTER TABLE是高危操作。实验中强调“修改表结构时需谨慎以防数据丢失”这不是吓唬人。在真实项目中一次ALTER COLUMN导致千万级数据截断的事故并不少见。所以规范做法是先SELECT TOP 1000检查数据分布再在测试库验证最后才上生产——这份实验报告就是你第一次拿“手术刀”前的模拟训练。3.4 触发器当约束不够用时数据库的“自动应答机器人”CHECK约束能管住单行数据但管不住跨表逻辑。比如“学生退课后其所在班级的‘已选课人数’字段要自动减1”。这种涉及多表、带业务逻辑的操作就需要触发器Trigger——它像一个埋在数据库里的微型程序一旦指定事件INSERT/UPDATE/DELETE发生就自动执行预设SQL。虽然实验报告中只提到“了解触发器的机制和使用”但它的存在意义重大约束是“静态规则”成绩必须0-100触发器是“动态响应”当成绩被修改自动更新该生的总分、排名、预警状态。它让数据库从“被动存储”升级为“主动服务”。一个成熟的教务系统背后往往有几十个触发器在默默运转确保数据生态的自洽。4. 索引不是“加速器”而是数据库的“导航地图”为什么加了索引查询快十倍写入却变慢4.1 索引的本质不是复制数据而是建立“快速定位目录”你可以把一张没有索引的表想象成一本没目录、没页码、按入库顺序堆起来的电话簿。查“张立”的电话只能一页页翻全表扫描。而索引就是数据库为你额外编制的一本“按姓名排序的目录”——它不存完整信息只存“姓名→页码”的映射。实验中创建的索引-- 为Course表的Cname字段建普通索引加速按课程名查询 CREATE INDEX iCname ON Course(Cname); -- 为Student表的Sname字段建唯一索引既加速查询又保证姓名不重复 CREATE UNIQUE INDEX iSname ON Student(Sname); -- 为Sc表的(Sno,Cno)建聚簇索引决定数据物理存储顺序主键默认就是聚簇索引 CREATE CLUSTERED INDEX iSnoCno ON Sc(Sno,Cno DESC);这里的关键区别普通索引iCname额外建一本“姓名目录”原电话簿不变唯一索引iSname这本目录还自带“查重”功能插入重名时直接报错聚簇索引iSnoCno它不单是目录而是直接重排电话簿的物理页码顺序——所有数据按(Sno,Cno)排好所以查询“某学生的所有选课”时数据天然连续速度最快。4.2 为什么索引越多写入越慢——数据库的“实时更新账本”代价索引加速查询但绝非免费午餐。每次INSERT/UPDATE/DELETE数据库不仅要改原表数据还要同步更新所有相关索引。就像你每新增一条电话记录除了写进电话簿还得在“姓名目录”里加一条新索引在“学号目录”里加一条在“课程号目录”里加一条……实验中创建了4个索引看似不多但在高并发场景下这会显著拖慢写入性能。因此索引设计是权衡的艺术高频查询字段如WHERE条件、JOIN字段、ORDER BY字段必须建索引极少查询的字段如“备注”“简历”绝不建索引更新极其频繁的字段如“点击量”“在线状态”建索引要极度谨慎。提示实验中让你CREATE INDEX后立即SELECT测试就是在感受“索引生效”的即时反馈。这种“动手即见效果”的体验是理解索引价值最直接的方式。4.3 聚簇索引为什么它只能有一个且通常交给主键聚簇索引之所以特殊在于它决定了数据在磁盘上的物理存储顺序。一个电话簿只能按一种方式排序要么按姓名要么按学号不能同时按两种。同理一张表只能有一个聚簇索引。实验中Sc表的主键是(Sno,Cno)所以默认聚簇索引就建在这两个字段上。这非常合理学生查自己的所有选课WHERE Sno20100001→ 数据物理连续秒出教师查某门课所有学生WHERE Cno1→ 虽然Cno不是首位但(Sno,Cno)的组合索引仍能高效定位。但如果错误地把聚簇索引建在Score上会导致所有数据按成绩排序存储Sno20100001的记录被分散在各处查一个学生所有课要扫全表每次插入新成绩数据库都要把整行数据挪到“成绩对应的位置”写入性能暴跌。所以聚簇索引的选择本质是选择“最常被用来范围查询或等值查询的字段组合”。对Sc表(Sno,Cno)就是最优解。4.4 如何判断该不该加索引——看执行计划而不是猜新手常犯的错是“觉得这个字段常查就加索引”。但真正决策依据是数据库的执行计划Execution Plan。SQL Server Management StudioSSMS中按CtrlL就能看到SQL实际怎么执行如果计划里出现Clustered Index Scan或Table Scan全表扫描说明没走索引是性能瓶颈如果出现Index Seek索引查找说明精准命中效率最优如果出现Key Lookup键查找说明索引没覆盖所有需要的字段还得回原表查效率打折。实验虽未要求看执行计划但它埋下了伏笔当你未来优化一个慢查询时这个技能就是你的“X光机”能一眼照出病灶在哪。而这份报告里反复练习的CREATE INDEX就是你第一次拿起“听诊器”的练习。5. 常见误区与易混概念初学者最常栽跟头的5个“坑”现在避开省下三个月调试时间5.1 “DELETE FROM table” vs “TRUNCATE TABLE”清空表到底哪个更快哪个能撤回易混点都写着“删除所有数据”以为只是写法不同。为什么混名字都带“删”结果看起来一样表空了。怎么区分DELETE FROM Student逐行删除每删一行都记日志可回滚ROLLBACK触发器会执行。适合需要审计、或要配合触发器的场景。TRUNCATE TABLE Student直接释放数据页不记逐行日志不可回滚不触发触发器速度极快。适合初始化测试数据。实验中用的是DELETE如delete from Student where Sno20100022因为它要精准删除某行且需保证事务一致性。若真要清空TRUNCATE才是正解——但实验不教是怕你误用。5.2 “WHERE” 和 “HAVING”都是“筛选”为什么一个在JOIN前一个在GROUP BY后易混点都写WHERE xxx和HAVING xxx以为只是关键字不同。为什么混中文都叫“筛选”初学时没意识到SQL执行顺序。怎么区分WHERE在分组前筛选原始行如WHERE SdeptCS先挑出计算机系学生HAVING在分组后筛选分组结果如HAVING AVG(Score)90是挑出“平均分超90的课程”。关键口诀WHERE 过滤行HAVING 过滤组。实验中SELECT Cno,AVG(Score) FROM Sc GROUP BY Cno HAVING AVG(Score)90如果写成WHERESQL Server会直接报错“聚合函数不能出现在WHERE子句中”。5.3 “INNER JOIN” vs “LEFT JOIN”只差一个字结果可能天壤之别易混点都叫“连接”以为只是多连或少连。为什么混没想清楚“以哪张表为基准”。怎么区分INNER JOIN只返回两张表都有匹配的行如只返回“选了课的学生”LEFT JOIN以左表为基准左表所有行都返回右表无匹配则补NULL如返回“所有学生”没选课的显示成绩为NULL。实验中特意做了对比SELECT * FROM Student,Sc WHERE...隐式内连接 vsSELECT * FROM Student LEFT JOIN Sc...。前者漏掉“未选课学生”后者不漏——这是做“学生覆盖率报表”的生死线。5.4 “COUNT(*)” vs “COUNT(字段)”统计人数为什么有时结果差很多易混点都统计数量以为结果一样。为什么混没注意NULL的特殊性。怎么区分COUNT(*)统计所有行数不管字段是否为NULLCOUNT(Score)只统计Score非NULL的行数如Score IS NULL的记录不计入。实验中SELECT COUNT(*) FROM Student和SELECT COUNT(Score) FROM Sc对比就是让你亲眼看到Sc表里有NULL成绩COUNT(Score)就比COUNT(*)少。这是统计“应考人数”vs“实考人数”的核心区别。5.5 “PRIMARY KEY” vs “UNIQUE NOT NULL”主键和唯一约束到底差在哪易混点都保证唯一都非空以为只是命名不同。为什么混没理解主键的“核心地位”。怎么区分PRIMARY KEY一张表只能有一个且自动创建聚簇索引默认是表的“身份证”UNIQUE一张表可有多个不自动建聚簇索引只是保证字段值不重复如邮箱、手机号。实验中Student表的Sno是PRIMARY KEY而Course表的Cname是UNIQUE课程名不能重复但不是主键。如果你把Cname设为主键那Cno课程号就不能做外键引用了——因为外键必须引用主键或唯一约束但主键只能有一个。6. 什么时候该用这份实验资源什么时候该果断放下——一个真实踩坑案例带来的血泪经验去年某高校实验室开发一套毕业设计选题系统。A同学负责数据库模块自信满满“不就是建几张表嘛我照着网上教程半小时搞定。”他快速建了Student、Teacher、Project三张表字段随便填主键随手设约束一个没加。上线第一天问题就来了学生张三提交了两次同一课题系统没拦住缺唯一约束教师李四修改自己职称时把Title字段填成了“教授/副教授”结果导出Excel全是乱码缺字符集定义和长度限制最致命的是管理员执行UPDATE Project SET Status已审核 WHERE ID123时忘了加WHERE条件全表Status被刷成“已审核”缺事务保护和备份习惯。系统瘫痪三天A同学通宵补数据、写道歉信。后来导师甩给他这份太原理工的实验报告“从第一章一个字一个字重新敲。”他照做了。这一次他严格按实验步骤建表阶段先写CREATE TABLE草稿明确每个字段的NOT NULL、CHECK、DEFAULT主键和外键用REFERENCES写死插入阶段不直接INSERT INTO ... VALUES而是先SELECT * FROM Student确认表结构再用INSERT INTO Student(Sno,Sname,...)显式列出字段避免顺序错修改阶段所有UPDATE和DELETE强制先写SELECT验证条件比如UPDATE Project SET Status已审核 WHERE ID123之前必先执行SELECT * FROM Project WHERE ID123确认目标唯一索引阶段在WHERE和JOIN字段上用CREATE INDEX加索引但绝不给TEXT或VARCHAR(MAX)字段建索引备份阶段每次重大操作前用SELECT * INTO Project_backup_20240520 FROM Project备份快照。两周后系统稳定上线。当看到“学生提交课题”按钮点击后数据库日志里清晰打印出INSERT成功、CHECK通过、FOREIGN KEY验证无误他长舒一口气——那种掌控感是任何理论课都给不了的。从那以后我每次设计数据库都强制走一遍这份实验报告的全流程先问“哪些字段绝对不能为空” → 加NOT NULL再问“哪些值必须在合法范围内” → 加CHECK接着问“哪张表是核心其他表要认它作爹” → 设PRIMARY KEY和FOREIGN KEY最后问“用户最常按什么查” → 给那些字段建索引。这不是繁琐而是把“数据不出错”从一句口号变成可执行、可验证、可传承的工程习惯。这份报告的价值不在于它教你写了多少行SQL而在于它用最朴素的方式告诉你在数字世界里真正的自由永远诞生于清晰的边界之内。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?