ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

数据库实验四:T-SQL约束与级联引用完整性实战指南

数据库实验四:T-SQL约束与级联引用完整性实战指南 简介这份数据库实验四文档面向高校数据库课程学习者聚焦T-SQL语句在完整性约束中的实际应用帮助读者掌握主键、唯一约束、引用完整性与级联引用的操作与验证方法。资源包内含1个docx文件大小约711KB以实验报告形式呈现涵盖课内任务与课外练习的完整记录。文档详细展示了联合主键的创建与删除、dept表唯一约束的移除、主表与从表增删改操作对参照完整性的影响以及级联更新失败的提示信息与原因分析并附有思考题解答如约束被拒绝时应给出合理提示而非删除约束、添加主键或外键出错的原因排查等。目前已有343人学习下载适合正在完成数据库实验或需要理解参照完整性、外键约束与级联更新机制的读者参考可帮助快速定位操作报错原因并理清约束设计思路。1. 数据库实验四拆解从 T-SQL 约束到级联引用一份能直接复现的完整性实验笔记如果你正在做数据库实验四大概率会被那几个报错信息卡住——UPDATE 语句与 REFERENCE 约束FK__person__DeptNo__2B0A656D冲突、UPDATE 语句与 FOREIGN KEY 约束fk_no冲突。这些不是玄学是 SQL Server 在告诉你你正在破坏参照完整性。这份实验文档围绕 T-SQL 的主键、唯一约束、外键和级联引用展开课内任务覆盖了创建/删除约束、测试主表与从表的增删改影响课外任务则把级联更新单独拎出来做压力测试。它适合正在上数据库课程、需要交实验报告的学生也适合想重新梳理约束机制、搞清楚“为什么外键不能级联更新”的从业者。下面我按实际动手顺序把每一步的语句、参数和踩坑点拆开讲。2. 主键与唯一约束T-SQL 语句怎么写、参数怎么定2.1 联合主键的创建与删除pay 表的 No、Year、Month实验要求把pay表的No、Year、Month三列联合定义为主键。联合主键的意思是这三列的组合值必须唯一单看某一列可以重复但三列拼在一起不能有重复行。常见做法是用ALTER TABLE加ADD CONSTRAINT语法如下-- 创建联合主键约束名 PK_pay 由自己指定 ALTER TABLE pay ADD CONSTRAINT PK_pay PRIMARY KEY (No, Year, Month);逻辑说明ALTER TABLE pay指定要修改的表ADD CONSTRAINT PK_pay是给新约束起名名字在数据库内必须唯一PRIMARY KEY (No, Year, Month)声明这三列组成主键。参数上要注意主键列不允许 NULL如果pay表里已有数据且这三列存在 NULL 或重复组合语句会直接报错。我一般会先跑一句SELECT No, Year, Month, COUNT(*) FROM pay GROUP BY No, Year, Month HAVING COUNT(*) 1看看有没有重复再执行添加。删除主键用DROP CONSTRAINT-- 删除联合主键 ALTER TABLE pay DROP CONSTRAINT PK_pay;这里PK_pay必须和创建时的约束名完全一致。如果你忘了名字可以查sys.key_constraints视图SELECT name FROM sys.key_constraints WHERE parent_object_id OBJECT_ID(pay)。删除主键本身不会删数据但如果有外键引用了这个主键必须先删外键才能删主键否则会报“因为有一个或多个对象访问此列ALTER TABLE DROP COLUMN 失败”之类的错误。2.2 唯一约束的删除dept 表部门名称列唯一约束和主键的区别在于唯一约束允许 NULL 值但只能有一个 NULL而且一个表可以有多个唯一约束。实验要求删除dept表部门名称列上的唯一约束。先确认约束名常见命名是UK_DeptName或系统自动生成的UQ__dept__...。查询语句-- 查找 dept 表上的唯一约束名 SELECT name, COL_NAME(ic.object_id, ic.column_id) AS column_name FROM sys.key_constraints kc JOIN sys.index_columns ic ON kc.parent_object_id ic.object_id AND kc.unique_index_id ic.index_id WHERE kc.parent_object_id OBJECT_ID(dept) AND kc.type UQ;拿到名字后删除-- 删除唯一约束约束名替换为上一步查到的实际名称 ALTER TABLE dept DROP CONSTRAINT UK_DeptName;参数说明type UQ过滤出唯一约束type PK则是主键。如果直接写DROP CONSTRAINT但名字不对会提示“找不到约束”。血泪经验是很多教材给的约束名和实际数据库里的不一致因为 SQL Server 自动生成的名字带哈希后缀所以先查再删别硬背。2.3 创建唯一约束的补充写法虽然实验只要求删除但报告里通常要对比创建语句。创建唯一约束的写法-- 在 dept 表的 DepartmentName 列上创建唯一约束 ALTER TABLE dept ADD CONSTRAINT UK_DeptName UNIQUE (DepartmentName);注意如果DepartmentName列已有重复值添加会失败报错信息会指出哪个值重复。解决方法是先清理重复数据或者改用UNIQUE NONCLUSTERED指定非聚集索引。参数上UNIQUE默认创建唯一非聚集索引如果表上已有聚集索引这个唯一约束就会自动变成非聚集的。3. 参照完整性测试主表与从表操作到底谁拦谁3.1 主表更新被拒dept 改部门代号person 失去参照实验第三步把dept表的部门代号00101改为00108结果失败报错UPDATE 语句与 REFERENCE 约束FK__person__DeptNo__2B0A656D冲突。这个报错的意思是person表里有一列DeptNo作为外键引用了dept表的DeptNo你改主表的被引用值从表里对应的00101就找不到参照对象了所以 SQL Server 直接拒绝。操作语句-- 尝试更新主表 dept 的部门代号 UPDATE dept SET DeptNo 00108 WHERE DeptNo 00101;执行后报错验证结果是“未完成主表 dept 更新操作影响从表 person”。这里的关键参数是WHERE DeptNo 00101确保只改目标行。如果改成00108之前从表person里已经有00108的记录那即使没有外键约束也可能造成数据混乱。常见做法是先查从表有没有引用00101再决定是改从表还是加级联。3.2 从表更新被拒pay 表工号改动违背外键实验第四步把pay表的工号000002改为000020失败报错UPDATE 语句与 FOREIGN KEY 约束fk_no冲突。pay表是person表的从表No列作为外键引用person表的No。你把从表的外键值改成主表里不存在的值参照完整性就被破坏。-- 尝试更新从表 pay 的工号 UPDATE pay SET No 000020 WHERE No 000002;参数说明WHERE No 000002定位原记录。报错原因是000020在person表的No列里不存在。验证结果写的是“修改从表的 No不是从主表 person 参照所得违背了参照完整性”。我一般会先跑SELECT No FROM person WHERE No 000020如果返回空就别执行更新否则必报错。3.3 级联引用设置与测试主表改从表跟着改实验第五步设置级联引用再把dept的00101改为00108这次成功了从表person里的00101也自动变成00108。级联更新通过外键的ON UPDATE CASCADE实现。先删旧外键再重建-- 删除原有外键约束名字以实际查询为准 ALTER TABLE person DROP CONSTRAINT FK__person__DeptNo__2B0A656D; -- 重建外键并启用级联更新 ALTER TABLE person ADD CONSTRAINT FK_person_dept FOREIGN KEY (DeptNo) REFERENCES dept(DeptNo) ON UPDATE CASCADE;逻辑说明FOREIGN KEY (DeptNo)指定从表的外键列REFERENCES dept(DeptNo)指定主表和被引用列ON UPDATE CASCADE表示主表被引用值更新时从表对应值自动更新。参数上还可以加ON DELETE CASCADE实现级联删除但实验只要求更新。注意如果从表里存在主表没有的DeptNo值重建外键会失败必须先清理脏数据。测试语句-- 再次尝试更新主表 UPDATE dept SET DeptNo 00108 WHERE DeptNo 00101; -- 查询从表验证级联效果 SELECT DeptNo FROM person WHERE DeptNo 00108;如果person表里出现了00108说明级联更新生效。这里有个坑级联更新不会触发从表的UPDATE触发器如果你有触发器逻辑需要额外处理。4. 避坑与排查约束报错、级联失败、外键冲突的常见问题4.1 现象添加主键时报“某语句与某列冲突”原因现有数据不符合主键要求比如pay表的No, Year, Month组合有重复或者某列有 NULL。解决先查重复SELECT No, Year, Month, COUNT(*) FROM pay GROUP BY No, Year, Month HAVING COUNT(*) 1再查 NULLSELECT * FROM pay WHERE No IS NULL OR Year IS NULL OR Month IS NULL。清理后再加约束。4.2 现象添加外键时报“某语句与某列冲突”原因从表里已有的外键值在主表里找不到对应。比如sc表的cno想引用course的cno但sc里存在course没有的课程号。解决先跑SELECT cno FROM sc WHERE cno NOT IN (SELECT cno FROM course)把孤儿记录删掉或补全主表数据再加外键。4.3 现象级联更新失败报错依旧原因外键约束没有真正启用ON UPDATE CASCADE或者旧外键没删干净就重建导致新约束没生效。解决查sys.foreign_keys确认update_referential_action_desc是否为CASCADESELECT name, update_referential_action_desc FROM sys.foreign_keys WHERE parent_object_id OBJECT_ID(person);如果显示NO_ACTION说明级联没设上需要删掉重建。4.4 现象删除主表数据时从表没跟着删原因只设了ON UPDATE CASCADE没设ON DELETE CASCADE。解决重建外键时同时加ON DELETE CASCADE。但注意如果从表还有下一级从表级联删除会连锁反应可能删掉大量数据生产环境慎用。4.5 现象约束名记不住DROP 一直报找不到原因SQL Server 自动生成的约束名带哈希后缀和教材写的不一样。解决用sys.key_constraints和sys.foreign_keys查实际名字别硬背。我习惯把查询语句存成片段每次先查再删。5. 课外任务进阶外键级联更新的边界与手动保证数据正确性课外任务里有一个关键结论外键不能实现级联更新在某些场景下需要用别的方法保证数据正确性。实验指导书 P44 的练习里修改sc表外键定义列cno引用course的cno并级联更新测试发现0809023501改为0809023601时级联更新失败。为什么因为sc表可能还有另一个外键cpno引用course的cno而course表的cpno又引用自己的cno形成自引用。SQL Server 不允许在自引用外键上设置级联更新会直接报错。那怎么保证数据正确性我一般走三步第一更新外键前先确认主表存在目标值。比如要把sc.cno从0809023501改成0809023601先跑SELECT cno FROM course WHERE cno 0809023601有结果才继续。第二用事务包住主表和从表的更新手动模拟级联BEGIN TRANSACTION; -- 先更新从表指向新值 UPDATE sc SET cno 0809023601 WHERE cno 0809023501; -- 再更新主表 UPDATE course SET cno 0809023601 WHERE cno 0809023501; COMMIT;参数说明BEGIN TRANSACTION开启事务任何一步失败就ROLLBACK避免中间状态。注意顺序先改从表再改主表否则主表改了从表还没改外键约束会立刻拦截。第三插入和删除同理。插入从表数据前确保主表有对应键值删除主表前先删从表引用或设ON DELETE CASCADE。如果外键不能级联更新就用触发器或存储过程兜底但触发器调试成本高我一般优先用事务手动控制。验证方法改完后跑一遍参照完整性检查-- 检查 sc 表是否有孤儿记录 SELECT sc.cno FROM sc LEFT JOIN course ON sc.cno course.cno WHERE course.cno IS NULL;返回空结果集才算干净。从那以后我每次做外键更新都强制先跑一遍孤儿检查再开事务最后再查一次三遍下来基本不会翻车。希望帮到你。本文还有配套的精品资源点击获取
返回列表