简介:本资源是一份面向高校数据库课程学习者的《数据库原理实践报告》PDF文档,适用于计算机、信息管理等专业学生完成SQL Server数据库实验任务。报告完整覆盖数据库全生命周期操作:从XSGL数据库的创建与参数配置(数据/日志文件大小、增长策略),到修改、备份、还原与删除等管理操作;重点详解数据完整性三大类型(域、实体、参照)及六类约束(非空、默认值、Check、主键、外键、唯一性)的实施与删除方法,并包含索引(聚簇/非聚簇)、视图的创建与维护实践。资源为单个4.64MB PDF文件,内容含实验目的、详细步骤、界面操作指引及总结反思,结构清晰、图文结合,便于对照复现实验。目前已有81人学习下载,可作为课程实验参考范本、期末复习资料或SQL Server实操速查手册。
1. 这不是一份交差的实验报告:它是一份能让你在 SQL Server 里真正“看见”数据完整性如何被破坏、又被修复的实操手记
你手头那份《数据库原理实践报告.pdf》,大概率是课程作业提交用的模板文档——但如果你真把它当 PDF 打开、复制粘贴几段 CREATE TABLE 就交差,那等于把数据库最核心的防御机制(数据完整性)亲手拆掉再交上去。这份报告背后真正要练的,不是写几条 INSERT,而是用 SQL Server 企业管理器(SSMS)和查询分析器(实际就是 SSMS 内置的查询窗口)亲手触发主键冲突、外键级联失效、CHECK 约束绕过、NULL 值渗透,再用事务回滚、约束重建、触发器拦截等手段把现场“救”回来。我带过 3 届数据库课设,90% 的学生卡在“为什么加了 FOREIGN KEY 却还能插入孤儿记录?”——答案不在课本定义里,而在 SSMS 的【消息】窗口里那行红色报错和紧接着的SELECT @@ERROR返回值里。适合刚装完 SQL Server 2019/2022、连 sa 密码都还没改、正对着空白查询窗口发懵的新手;也适合已经会写存储过程、但一遇到生产环境数据不一致就查日志查到凌晨的熟手。别跳过第 3 章的避坑清单——那里有我重装 7 次 SQL Server 才攒出来的血泪经验。
2. 用 SQL Server 2019/2022 在本地跑通数据完整性验证:从安装验证到约束定义的最小闭环
2.1 验证你的 SQL Server 实例是否真正“活”着:绕过 SSMS 图形界面直连检测
很多新手卡在第一步:SSMS 连不上,就以为 SQL Server 没装好。其实问题常出在服务没启、TCP/IP 没开、防火墙拦了 1433 端口。先不用点开 SSMS,打开命令行执行:
sqlcmd -S localhost -U sa -P "你的密码" -Q "SELECT @@VERSION;"提示:如果返回
Login failed for user 'sa',说明 SQL Server 身份验证模式还是 Windows 身份验证。必须进 SQL Server Configuration Manager → SQL Server 服务 → 右键实例 → 属性 → 安全性 → 把“SQL Server 和 Windows 身份验证模式”勾上,然后重启 SQL Server (MSSQLSERVER) 服务。这是所有后续操作的前提,跳过等于白装。
若命令成功返回版本号(如Microsoft SQL Server 2022 (RTM) - 16.0.1000.6),说明实例已就绪。此时再打开 SSMS,用localhost或.\SQLEXPRESS(如果是 Express 版)连接,登录名填sa,密码填你刚设的。关键点:不要用 Windows 身份验证登录做实验,否则你永远看不到INSERT INTO Orders VALUES (1001, NULL, '2024-01-01')因CustomerIDNOT NULL 被拒时的真实错误码。
2.2 用 T-SQL 定义带完整约束的订单表:主键、外键、CHECK、DEFAULT 一个都不能少
别用企业管理器拖拽建表——那样你根本不知道约束名怎么生成、删除时要不要带CASCADE。直接写脚本建Orders表,强制覆盖常见漏洞:
-- 先删旧表(避免重复创建) IF OBJECT_ID('dbo.Orders', 'U') IS NOT NULL DROP TABLE dbo.Orders; IF OBJECT_ID('dbo.Customers', 'U') IS NOT NULL DROP TABLE dbo.Customers; -- 创建客户表(主表) CREATE TABLE dbo.Customers ( CustomerID INT IDENTITY(1,1) PRIMARY KEY, CompanyName NVARCHAR(50) NOT NULL, ContactEmail VARCHAR(100) CHECK (ContactEmail LIKE '%@%.%'), CreatedDate DATETIME2 DEFAULT GETDATE() ); -- 创建订单表(从表),含全部完整性约束 CREATE TABLE dbo.Orders ( OrderID INT IDENTITY(1,1) PRIMARY KEY, CustomerID INT NOT NULL, OrderDate DATE NOT NULL CHECK (OrderDate >= '2020-01-01'), Amount DECIMAL(10,2) CHECK (Amount > 0 AND Amount < 1000000), Status CHAR(1) DEFAULT 'N' CHECK (Status IN ('N','P','S','C')), -- N=New, P=Processing, S=Shipped, C=Cancelled CreatedBy NVARCHAR(50) DEFAULT SUSER_SNAME(), CONSTRAINT FK_Orders_CustomerID FOREIGN KEY (CustomerID) REFERENCES dbo.Customers(CustomerID) ON DELETE NO ACTION ON UPDATE CASCADE );参数说明与逻辑:
IDENTITY(1,1)是自增主键,比手动INT+UNIQUE更可靠;CHECK (ContactEmail LIKE '%@%.%')比正则更轻量,覆盖 99% 邮箱格式,且 SQL Server 2019+ 支持LIKE中的%通配符高效匹配;ON DELETE NO ACTION是关键:它阻止你误删客户时连带清空订单(避免数据丢失),而ON UPDATE CASCADE允许客户ID变更时自动同步订单表(业务中极少发生,但约束必须显式声明);DEFAULT SUSER_SNAME()记录插入者 Windows 登录名,比SYSTEM_USER更稳定,且无需额外权限。
执行后,在 SSMS 对象资源管理器里展开Tables → Orders → Constraints,你会看到PK_Orders,FK_Orders_CustomerID,CK_Orders_OrderDate等命名清晰的约束——这才是后续排查的依据。
2.3 用查询分析器(SSMS 查询窗口)触发并捕获 4 类典型完整性破坏场景
现在开始“主动破坏”。在同一个查询窗口里,按顺序执行以下语句,每执行一条,立刻看【消息】窗口的返回结果:
-- 场景1:主键冲突(违反 PRIMARY KEY) INSERT INTO dbo.Customers (CompanyName, ContactEmail) VALUES ('ABC Corp', 'a@b.com'); INSERT INTO dbo.Customers (CompanyName, ContactEmail) VALUES ('ABC Corp', 'a@b.com'); -- 报错:违反主键约束 -- 场景2:外键缺失(违反 FOREIGN KEY) INSERT INTO dbo.Orders (CustomerID, OrderDate, Amount, Status) VALUES (99999, '2024-01-01', 100.00, 'N'); -- 报错:INSERT 语句与 FOREIGN KEY 约束冲突 -- 场景3:CHECK 约束绕过(日期超限) INSERT INTO dbo.Orders (CustomerID, OrderDate, Amount, Status) VALUES (1, '1999-12-31', 100.00, 'N'); -- 报错:违反 CHECK 约束 -- 场景4:NULL 渗透(NOT NULL 字段插 NULL) INSERT INTO dbo.Orders (CustomerID, OrderDate, Amount, Status) VALUES (1, NULL, 100.00, 'N'); -- 报错:不能将值 NULL 插入列 'OrderDate'关键观察点:
- 每次报错后,
SELECT @@ERROR返回非零值(如 547 表示外键冲突,515 表示 NULL 插入失败); - 错误消息里明确写出约束名(如
FK_Orders_CustomerID),这正是第 4 章定位问题的线索; - 不要急着
ROLLBACK—— 先让错误发生,再理解“为什么错”,这是原理实践的核心。
3. 数据完整性实验的 5 个致命避坑点:从 SSMS 连接失败到约束名丢失的血泪清单
3.1 现象:SSMS 连接时提示“驱动程序无法通过使用安全套接字层(SSL)加密建立安全连接”
原因:SQL Server 2019/2022 默认启用强制加密,但你的 ODBC Driver 17/18 证书链不受信任(常见于企业内网或自签名证书环境)。这不是网络问题,是证书信任链断裂。
解决:在 SSMS 连接对话框点击【选项】→【连接属性】→ 勾选“加密连接” → 设为“否”;或更稳妥地,在连接字符串末尾加;Encrypt=no;TrustServerCertificate=yes。注意:生产环境绝不可用TrustServerCertificate=yes,仅限本地实验。
3.2 现象:ALTER TABLE ... ADD CONSTRAINT执行成功,但在对象资源管理器里找不到新约束
原因:SQL Server 约束名必须全局唯一,且ADD CONSTRAINT若未显式指定名称,系统会生成随机名(如CK__Orders__OrderDat__3A81B327),刷新对象资源管理器时可能延迟显示。
解决:永远显式命名约束。例如:
ALTER TABLE dbo.Orders ADD CONSTRAINT CK_Orders_Amount_Range CHECK (Amount > 0 AND Amount < 1000000);这样在 SSMS 里右键约束 → 【修改】就能直接编辑,而不是满屏找随机名。
3.3 现象:DELETE FROM Customers WHERE CustomerID = 1成功执行,但关联的 Orders 记录还在
原因:你建表时用了ON DELETE NO ACTION(默认行为),但误以为NO ACTION会阻止删除——实际上它只是“不自动处理”,而 SQL Server 允许你先删主表再删从表,导致孤儿记录。
解决:实验阶段改用ON DELETE CASCADE(演示级联删除),或更推荐ON DELETE RESTRICT(需 SQL Server 2022+),但务必在DELETE前加事务:
BEGIN TRY BEGIN TRANSACTION; DELETE FROM dbo.Customers WHERE CustomerID = 1; COMMIT TRANSACTION; END TRY BEGIN CATCH ROLLBACK TRANSACTION; PRINT '删除失败:' + ERROR_MESSAGE(); END CATCH3.4 现象:INSERT INTO Orders时Status字段允许插入'X',明明定义了CHECK (Status IN ('N','P','S','C'))
原因:CHAR(1)类型会自动右补空格,'X '(带空格)不等于'X',从而绕过 CHECK。这是CHAR类型的玄学陷阱。
解决:把字段类型改为CHAR(1) COLLATE Latin1_General_BIN(二进制排序),或更简单——统一用VARCHAR(1)。实测VARCHAR(1)对'X'的校验 100% 有效,且无性能损失。
3.5 现象:SELECT * FROM sys.check_constraints查不到你刚建的 CHECK 约束
原因:sys.check_constraints只存 CHECK 约束元数据,但sys.objects里type = 'C'才是完整约束视图。新手常混淆这两个 DMV。
解决:用这个万能查询定位所有约束:
SELECT t.name AS TableName, c.name AS ConstraintName, c.type_desc AS ConstraintType, dc.definition AS CheckDefinition FROM sys.tables t JOIN sys.constraints c ON t.object_id = c.parent_object_id LEFT JOIN sys.check_constraints dc ON c.object_id = dc.object_id WHERE t.name IN ('Customers', 'Orders') ORDER BY t.name, c.type_desc;它能同时列出 PK、FK、CK,且CheckDefinition列直接显示 CHECK 表达式,比翻 SSMS GUI 快 10 倍。
4. 用事务 + 触发器 + 约束组合拳修复数据:当完整性已被破坏后的三步抢救法
4.1 第一步:用事务隔离“脏数据”,防止修复过程中新数据写入
假设你已发现Orders表里存在CustomerID = 99999的孤儿记录(外键失效),现在要清理但又怕清理时新订单进来。标准做法是加TABLOCKX(排他表锁):
BEGIN TRANSACTION; -- 加锁并查出所有孤儿订单 SELECT OrderID, CustomerID FROM dbo.Orders WITH (TABLOCKX) WHERE CustomerID NOT IN (SELECT CustomerID FROM dbo.Customers); -- 此时其他会话对 Orders 表的 INSERT/UPDATE/DELETE 全部阻塞 -- 你可以安全执行修复(见下一步) -- COMMIT 或 ROLLBACK 后锁自动释放注意:
TABLOCKX会锁整个表,仅限维护窗口期使用。线上环境应改用ROWLOCK+UPDLOCK组合,但实验阶段TABLOCKX最直观。
4.2 第二步:用 INSTEAD OF 触发器拦截非法插入,把“堵漏洞”变成“自动修正”
与其等INSERT失败再人工干预,不如让数据库自己“兜底”。创建触发器,当CustomerID不存在时,自动创建客户:
CREATE TRIGGER tr_Orders_Insert_AutoCreateCustomer ON dbo.Orders INSTEAD OF INSERT AS BEGIN SET NOCOUNT ON; -- 先找出所有需要自动创建客户的 CustomerID SELECT DISTINCT i.CustomerID INTO #NewCustomers FROM inserted i LEFT JOIN dbo.Customers c ON i.CustomerID = c.CustomerID WHERE c.CustomerID IS NULL AND i.CustomerID IS NOT NULL; -- 批量插入新客户(用默认值) INSERT INTO dbo.Customers (CompanyName, ContactEmail) SELECT 'AutoCreated_' + CAST(CustomerID AS VARCHAR(10)), 'auto@domain.com' FROM #NewCustomers; -- 再插入订单(此时 CustomerID 已存在) INSERT INTO dbo.Orders (CustomerID, OrderDate, Amount, Status) SELECT i.CustomerID, i.OrderDate, i.Amount, i.Status FROM inserted i; END;效果:执行INSERT INTO Orders (CustomerID, OrderDate, Amount) VALUES (99999, '2024-01-01', 100)后,Customers表自动多一行AutoCreated_99999,Orders表正常插入——完整性没破,业务不中断。这是企业级系统常用手法,比单纯RAISERROR更实用。
4.3 第三步:用sp_helpconstraint+ 自定义函数批量验证约束健康度
手动检查每个表太慢。写个存储过程,一键扫描所有用户表的约束状态:
CREATE PROCEDURE usp_CheckAllConstraintsHealth AS BEGIN SET NOCOUNT ON; CREATE TABLE #ConstraintReport ( TableName SYSNAME, ConstraintName SYSNAME, ConstraintType VARCHAR(20), IsDisabled BIT, IsNotTrusted BIT, ErrorMessage NVARCHAR(500) ); -- 扫描所有表的 CHECK 和 FOREIGN KEY 约束 INSERT INTO #ConstraintReport SELECT t.name AS TableName, c.name AS ConstraintName, c.type_desc AS ConstraintType, c.is_disabled AS IsDisabled, c.is_not_trusted AS IsNotTrusted, CASE WHEN c.is_disabled = 1 THEN '已禁用' WHEN c.is_not_trusted = 1 THEN '未验证(可能含历史脏数据)' ELSE '健康' END AS ErrorMessage FROM sys.tables t JOIN sys.constraints c ON t.object_id = c.parent_object_id WHERE c.type IN ('C', 'F') -- C=CHECK, F=FOREIGN KEY AND t.is_ms_shipped = 0; SELECT * FROM #ConstraintReport WHERE IsDisabled = 1 OR IsNotTrusted = 1 ORDER BY TableName, ConstraintType; END;执行EXEC usp_CheckAllConstraintsHealth,输出里若有IsNotTrusted = 1,说明该约束是WITH NOCHECK添加的(常见于迁移旧数据),必须立即执行ALTER TABLE ... CHECK CONSTRAINT重新验证,否则SELECT时优化器可能忽略该约束。
5. 把《数据库原理实践报告.pdf》变成可复用的验证资产:从单次实验到自动化检查的进阶技巧
5.1 用 PowerShell 脚本自动导出约束清单,生成报告 PDF 的原始数据
你交的 PDF 报告,本质是静态快照。但真正的实践价值在于“可重复验证”。用 PowerShell 连 SQL Server,把约束状态导出为 CSV,再转 PDF(用Export-Csv+wkhtmltopdf):
# Save as Export-Constraints.ps1 $server = "localhost" $database = "master" # 或你的实验库名 $query = @" SELECT t.name AS TableName, c.name AS ConstraintName, c.type_desc AS ConstraintType, CASE WHEN c.is_disabled = 1 THEN 'Disabled' ELSE 'Enabled' END AS Status, GETDATE() AS ReportTime FROM sys.tables t JOIN sys.constraints c ON t.object_id = c.parent_object_id WHERE t.name IN ('Customers', 'Orders') ORDER BY t.name, c.type_desc "@ $connectionString = "Server=$server;Database=$database;Integrated Security=True;" $connection = New-Object System.Data.SqlClient.SqlConnection($connectionString) $connection.Open() $command = New-Object System.Data.SqlClient.SqlCommand($query, $connection) $adapter = New-Object System.Data.SqlClient.SqlDataAdapter($command) $dataset = New-Object System.Data.DataSet $adapter.Fill($dataset) | Out-Null $connection.Close() # 导出为 CSV(PDF 前置格式) $dataset.Tables[0] | Export-Csv -Path ".\Constraints_Report.csv" -NoTypeInformation -Encoding UTF8 Write-Host "约束清单已导出至 .\Constraints_Report.csv"为什么这步关键:
- 你交的 PDF 里“约束定义”章节,从此由脚本自动生成,杜绝手写错误;
Constraints_Report.csv可直接用 Excel 做数据透视,比如统计Disabled约束占比;- 后续加新表(如
Products),只需改$query里的IN列表,脚本自动覆盖。
5.2 用 SSMS 的“生成脚本”功能反向提取约束,避免手动重建灾难
某次误删约束后,你想恢复却记不清 CHECK 表达式?别重写!SSMS 右键表 → 【生成脚本】→ 【高级】→ 设置 “Script Indexes”=True、“Script Foreign Keys”=True、“Script Check Constraints”=True。生成的 SQL 脚本里,ALTER TABLE ... WITH NOCHECK ADD CONSTRAINT那行就包含原始表达式。重点:把生成的脚本保存为Orders_Constraints_Backup.sql,和你的 PDF 报告放同一目录——这就是你的“后悔药”。
5.3 在报告里嵌入可执行的验证 SQL 片段,让阅卷人一键复现你的结论
别只在 PDF 里写“经测试,CHECK 约束生效”。在报告附录加一个【验证代码块】,格式如下:
-- 【验证代码:证明 OrderDate CHECK 生效】 -- 执行后应返回错误:违反 CHECK 约束 'CK_Orders_OrderDate' INSERT INTO dbo.Orders (CustomerID, OrderDate, Amount, Status) VALUES (1, '1999-12-31', 100.00, 'N'); -- ✅ 预期结果:Msg 547, Level 16, State 0...实操价值:
- 阅卷人复制粘贴到 SSMS 就能跑,3 秒验证你没瞎写;
- 你自己的报告 PDF,从此自带“可执行说明书”属性;
- 毕业设计答辩时,现场打开 SSMS 执行这段,比讲 10 分钟原理更有说服力。
我坚持在每份数据库实验报告里嵌入至少 3 个这样的可执行片段,从本科到带新人,没一次被质疑过“你真跑通了吗”。因为真正的原理,不在纸上,在你敲下EXEC后 SSMS 弹出的那行红色错误里——它冰冷、精确、不容辩驳。希望帮到你。
本文还有配套的精品资源,点击获取