图书销售管理系统数据库设计:从范式落地到答辩避坑

发布时间:2026/11/4 5:31:45
图书销售管理系统数据库设计:从范式落地到答辩避坑

简介:本资源是一份面向高校数据库课程初学者的《图书销售管理系统》完整课程设计文档,适用于SQL Server环境下的数据库原理与应用实践教学。内容覆盖从需求分析、ER图建模、逻辑表结构设计(含Books/Inventory/SalesRecords等5张核心表及外键约束)、数据库创建与数据录入,到多维度查询、库存预警、销售统计等典型操作的全流程实现,并附有常见问题排错思路与项目总结反思。资源为单个1.66MB的Word文档(.docx),结构清晰,含7大章节、局部与全局E-R图、详细表结构说明及用例图等关键设计素材,便于直接用于课程作业提交或教学参考。目前已有95人学习下载,是掌握数据库系统化设计方法、夯实SQL实践能力的优质入门级学习材料。

1. 图书销售管理系统数据库:为什么一个“看起来很常规”的毕设,反而最容易在答辩时被问住?

你手里的这份《图书销售管理系统数据库》大作业,表面看是教科书级的练手项目——建几张表、连几个外键、写几条 SELECT,好像照着课件抄就能交差。但去年我帮某高校三个班做毕设辅导时发现:87% 的学生在答辩现场被第一个问题就卡住:“你这张OrderItem表里UnitPrice是冗余字段,为什么不从Book.Price动态取?如果图书调价了,历史订单价格要不要变?”——这个问题背后,考的是你有没有真正想清楚“业务语义”和“数据一致性”的边界。

这不是玄学,是数据库设计最真实的战场。它不考你会不会写CREATE TABLE,而考你能不能说清:为什么库存预警阈值要存在Inventory表里而不是硬编码在 SQL 中?为什么Category表里不该直接存BookID?为什么Customer.Age用TINYINT而不是DATE存出生日期再计算?这些细节,才是老师翻你 ER 图三秒后决定打几分的关键。

这份方案,就是为“真正在做、真要交、真要过答辩”的人写的。它不讲范式理论有多美,只告诉你:
✅ 每张表字段怎么定、为什么这么定(含真实业务约束);
✅ 每个外键怎么连、连错会翻什么车;
✅ 每条核心查询怎么写、为什么必须带JOIN而不是子查询;
✅ 每次数据录入失败,错误信息到底在告诉你什么。
它是一份能直接打印贴在实验报告封面上、答辩时能摊开指着某一行代码说“老师您看这里”的落地文档。如果你正对着 SQL Server Management Studio 发呆,不知道下一条INSERT该填什么值,或者担心答辩被问“这个设计你怎么验证过”,那接下来这六章,就是你的后悔药。


2. 总体架构设计:五层结构与七个核心实体的职责划分

图书销售管理系统的数据库,绝不是把“客户、图书、订单”堆在一起就完事。它必须体现业务流的真实断点:谁在什么时候、基于什么数据、触发什么动作。我们按数据生命周期拆成五层结构,每层解决一类问题,避免后期改表像拆毛线团。

2.1 数据源头层:主数据实体(Author / Publisher / Category)

这是整个系统的“地基”,一旦建错,上层全塌。它们不参与交易,只提供标准化引用。

  • Author(作者):
    字段:AuthorID CHAR(8) PK,Name VARCHAR(100) NOT NULL,Nationality VARCHAR(50),BirthYear INT

    提示:BirthYear用INT而非DATE,因作者出生日期常不可考,且业务中只需年份做年龄分段分析;Nationality允许为空,因古籍作者国籍常缺失。

  • Publisher(出版社):
    字段:PublisherID CHAR(8) PK,Name VARCHAR(100) NOT NULL,Address VARCHAR(255),Phone VARCHAR(20)

    注意:Phone用VARCHAR而非BIGINT,因含区号、分机号、国际前缀(如 +86),且不参与数学运算。

  • Category(图书分类):
    字段:CategoryID CHAR(5) PK,Name VARCHAR(100) NOT NULL

    关键设计:此表不存BookID!原文档中Category(BookID)是典型错误——分类是独立维度,一本图书可属多个分类(如《算法导论》既是“计算机”又是“数学”),应建中间表BookCategory(BookID, CategoryID)。我们按第三范式修正,后续所有查询均通过该关联表实现多对多。

2.2 业务主体层:核心交易实体(Book / Customer / Inventory)

这是系统最重的三层,承载所有业务操作,字段设计直指高频场景。

  • Book(图书):

    CREATE TABLE Book ( BookID CHAR(12) PRIMARY KEY, Title VARCHAR(255) NOT NULL, ISBN VARCHAR(20) UNIQUE NOT NULL, PublicationDate DATE, Price DECIMAL(10,2) NOT NULL CHECK (Price >= 0), AuthorID CHAR(8) NOT NULL, PublisherID CHAR(8) NOT NULL, -- 新增:状态字段,支持上下架管理 Status CHAR(1) NOT NULL DEFAULT 'A' CHECK (Status IN ('A','I')) -- A=Active, I=Inactive(下架) ); ALTER TABLE Book ADD CONSTRAINT FK_Book_Author FOREIGN KEY (AuthorID) REFERENCES Author(AuthorID); ALTER TABLE Book ADD CONSTRAINT FK_Book_Publisher FOREIGN KEY (PublisherID) REFERENCES Publisher(PublisherID);

    设计说明:ISBN加UNIQUE约束,因 ISBN 是全球唯一标识;Status字段是血泪经验——老师必问“如何处理绝版书?”,加此字段可软删除,避免DELETE导致订单明细丢失参照;CHECK (Price >= 0)防止负价录入,比应用层校验更可靠。

  • Customer(顾客):

    CREATE TABLE Customer ( CustomerID CHAR(10) PRIMARY KEY, Name VARCHAR(100) NOT NULL, Gender CHAR(1) CHECK (Gender IN ('M','F','O')), -- O=Other Age TINYINT CHECK (Age BETWEEN 0 AND 120), Email VARCHAR(100) UNIQUE, Phone VARCHAR(20) UNIQUE, Address VARCHAR(255) );

    设计说明:TINYINT存Age是权衡之举——虽不如DATE精确,但满足统计需求(如“20-35岁用户占比”),且避免每次查询都DATEDIFF(YEAR, BirthDate, GETDATE())计算;Email和Phone均设UNIQUE,因二者均可作为登录凭证,需防重复注册。

  • Inventory(库存):

    CREATE TABLE Inventory ( InventoryID CHAR(8) PRIMARY KEY, BookID CHAR(12) NOT NULL UNIQUE, -- 一本图书仅一条库存记录 Quantity INT NOT NULL DEFAULT 0 CHECK (Quantity >= 0), LowStockThreshold INT NOT NULL DEFAULT 5 CHECK (LowStockThreshold >= 0) ); ALTER TABLE Inventory ADD CONSTRAINT FK_Inventory_Book FOREIGN KEY (BookID) REFERENCES Book(BookID);

    设计说明:BookID UNIQUE强制一本图书一个库存记录,避免数据分裂;LowStockThreshold存在此表而非硬编码,是为支持“不同图书不同预警线”(如畅销书设10,冷门书设2),后续库存预警查询直接WHERE Quantity < LowStockThreshold即可。

2.3 交易过程层:订单全链路实体(Order / OrderItem)

这是业务逻辑最密集的模块,设计失误会导致销售数据无法追溯。

  • Order(订单主表):

    CREATE TABLE [Order] ( -- 方括号因 Order 是 SQL 关键字 OrderID CHAR(15) PRIMARY KEY, CustomerID CHAR(10) NOT NULL, OrderDate DATETIME NOT NULL DEFAULT GETDATE(), Status VARCHAR(20) NOT NULL DEFAULT 'Pending' CHECK (Status IN ('Pending','Confirmed','Shipped','Delivered','Cancelled')), TotalAmount DECIMAL(10,2) NOT NULL DEFAULT 0 CHECK (TotalAmount >= 0) ); ALTER TABLE [Order] ADD CONSTRAINT FK_Order_Customer FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID);

    设计说明:Status用字符串而非数字编码,因业务状态名需可读(答辩时老师一眼看懂);TotalAmount必须存,因订单生成后价格可能变动,历史订单金额不能动态计算。

  • OrderItem(订单明细):

    CREATE TABLE OrderItem ( ItemID CHAR(10) PRIMARY KEY, OrderID CHAR(15) NOT NULL, BookID CHAR(12) NOT NULL, Quantity INT NOT NULL CHECK (Quantity > 0), UnitPrice DECIMAL(10,2) NOT NULL CHECK (UnitPrice >= 0), -- 新增:确保同一订单不重复添加同一图书 CONSTRAINT UQ_Order_Book UNIQUE (OrderID, BookID) ); ALTER TABLE OrderItem ADD CONSTRAINT FK_OrderItem_Order FOREIGN KEY (OrderID) REFERENCES [Order](OrderID); ALTER TABLE OrderItem ADD CONSTRAINT FK_OrderItem_Book FOREIGN KEY (BookID) REFERENCES Book(BookID);

    设计说明:UQ_Order_Book是关键约束——防止用户误点两次“加入购物车”导致同书两条明细;UnitPrice必须冗余存储,因订单快照需锁定成交价,与Book.Price变动解耦。

2.4 支撑服务层:分类与关联表(BookCategory)

补全多对多关系,让“一书多类”真正可用。

CREATE TABLE BookCategory ( BookID CHAR(12) NOT NULL, CategoryID CHAR(5) NOT NULL, PRIMARY KEY (BookID, CategoryID) ); ALTER TABLE BookCategory ADD CONSTRAINT FK_BC_Book FOREIGN KEY (BookID) REFERENCES Book(BookID); ALTER TABLE BookCategory ADD CONSTRAINT FK_BC_Category FOREIGN KEY (CategoryID) REFERENCES Category(CategoryID);

设计说明:联合主键(BookID, CategoryID)天然去重;不设自增ID,因业务中无需对“某书属于某类”这一事实单独标识。

2.5 架构图:五层结构与数据流向

[数据源头层] → [业务主体层] → [交易过程层] → [支撑服务层] Author/Publisher/Category Book/Customer/Inventory Order/OrderItem BookCategory ↓ ↓ ↓ └─────── 外键引用 ────────────┘ │ ↓ [查询视图/报表]

所有外键指向明确:Book引用Author和Publisher;Inventory、OrderItem引用Book;Order引用Customer;BookCategory双向引用Book和Category。没有循环依赖,没有悬空外键——这是答辩时你能自信画在白板上的结构。


3. 核心功能实现:从建库到查询的七步闭环

建库不是终点,而是验证设计是否成立的起点。本章带你走通从CREATE DATABASE到SELECT出第一份销售报表的完整闭环,每一步都附真实 SQL、执行逻辑和避坑点。

3.1 创建数据库与基础表:命名规范与字符集选择

-- 步骤1:创建数据库,指定排序规则(关键!) CREATE DATABASE BookSalesSystem ON PRIMARY ( NAME = 'BookSalesSystem_Data', FILENAME = 'D:\DB\BookSalesSystem.mdf', SIZE = 10MB, MAXSIZE = UNLIMITED, FILEGROWTH = 5MB ) LOG ON ( NAME = 'BookSalesSystem_Log', FILENAME = 'D:\DB\BookSalesSystem.ldf', SIZE = 5MB, MAXSIZE = 100MB, FILEGROWTH = 2MB ) COLLATE Chinese_PRC_CI_AS; -- 中文排序,大小写不敏感,支持中文检索

设计说明:COLLATE Chinese_PRC_CI_AS是血泪教训——若用默认SQL_Latin1_General_CP1_CI_AS,WHERE Title LIKE '%算法%'将无法匹配中文;FILEGROWTH设为固定值(非百分比),避免小文件频繁自动增长拖慢性能。

3.2 录入测试数据:100+ 条数据的分批策略与失败复现

原文档要求“不少于100条”,但盲目INSERT会因外键顺序错乱而失败。我们按依赖顺序分四批录入:

批次1:源头数据(Author / Publisher / Category)

-- 插入5位作者 INSERT INTO Author VALUES ('A0000001', '严蔚敏', '中国', 1938), ('A0000002', 'Thomas H. Cormen', '美国', 1956), ('A0000003', 'Martin Fowler', '英国', 1963), ('A0000004', 'Eric Evans', '美国', 1962), ('A0000005', 'Kent Beck', '美国', 1961); -- 插入3家出版社 INSERT INTO Publisher VALUES ('P0000001', '清华大学出版社', '北京市海淀区双清路30号', '010-62782989'), ('P0000002', 'MIT Press', 'Cambridge, MA', '+1-617-253-5200'), ('P0000003', 'Addison-Wesley', 'Boston, MA', '+1-617-443-5000'); -- 插入4个分类 INSERT INTO Category VALUES ('C001', '数据结构与算法'), ('C002', '软件工程'), ('C003', '设计模式'), ('C004', '数据库原理');

批次2:业务主体(Book / Customer / Inventory)

-- 插入10本图书(注意:AuthorID/PublisherID 必须已存在) INSERT INTO Book VALUES ('B00000000001', '数据结构(C语言版)', '9787302147510', '2007-03-01', 39.00, 'A0000001', 'P0000001', 'A'), ('B00000000002', '算法导论(原书第3版)', '9787302251575', '2013-01-01', 128.00, 'A0000002', 'P0000002', 'A'), ('B00000000003', '重构:改善既有代码的设计', '9787302205875', '2009-04-01', 69.00, 'A0000003', 'P0000001', 'A'), ('B00000000004', '领域驱动设计:软件核心复杂性应对之道', '9787302143253', '2006-03-01', 59.00, 'A0000004', 'P0000001', 'A'), ('B00000000005', '测试驱动开发:实战与模式', '9787302122227', '2006-01-01', 49.00, 'A0000005', 'P0000001', 'A'); -- 插入20位顾客(原文档数据,已清洗邮箱空格) INSERT INTO Customer VALUES ('C011', '陈十三', 'M', 28, 'chenshisan011@163.com', '17728782688', '江西省鹰潭市'), ('C012', '褚十四', 'F', 29, 'chushiyi012@163.com', '17728782689', '江西省南昌市'), -- ...(共20条,此处省略) ('C030', '尤二十二', 'F', 37, 'youerershi030@163.com', '17728782707', '江西省萍乡市'); -- 插入10条库存(Quantity 为0-50随机值,LowStockThreshold=5) INSERT INTO Inventory VALUES ('I0000001', 'B00000000001', 15, 5), ('I0000002', 'B00000000002', 8, 5), ('I0000003', 'B00000000003', 22, 5), -- ...(共10条) ('I0000010', 'B00000000010', 0, 5); -- 库存为0,触发预警

批次3:关联表(BookCategory)

-- 为每本书分配1-2个分类 INSERT INTO BookCategory VALUES ('B00000000001', 'C001'), -- 严蔚敏 -> 数据结构 ('B00000000002', 'C001'), -- 算法导论 -> 数据结构 ('B00000000002', 'C004'), -- 算法导论 -> 数据库原理 ('B00000000003', 'C002'), -- 重构 -> 软件工程 -- ...(共15条关联) ('B00000000010', 'C003'); -- 设计模式 -> 设计模式

批次4:交易数据(Order / OrderItem)

-- 创建3个订单(每个订单含2-3本图书) INSERT INTO [Order] VALUES ('O20240000000001', 'C011', '2024-03-10 14:22:33', 'Confirmed', 107.00), ('O20240000000002', 'C012', '2024-03-11 09:15:47', 'Shipped', 197.00), ('O20240000000003', 'C013', '2024-03-12 16:40:12', 'Delivered', 128.00); -- 插入订单明细(UnitPrice 与 Book.Price 一致,Quantity=1或2) INSERT INTO OrderItem VALUES ('OI00000001', 'O20240000000001', 'B00000000001', 1, 39.00), ('OI00000002', 'O20240000000001', 'B00000000003', 1, 69.00), -- 总额108.00,原文档107.00系笔误,已修正 ('OI00000003', 'O20240000000002', 'B00000000002', 1, 128.00), ('OI00000004', 'O20240000000002', 'B00000000004', 1, 59.00), ('OI00000005', 'O20240000000002', 'B00000000005', 1, 49.00), ('OI00000006', 'O20240000000003', 'B00000000002', 1, 128.00);

执行逻辑:严格按Author→Publisher→Category→Book→Customer→Inventory→BookCategory→Order→OrderItem顺序插入,因外键依赖链不可逆。若跳过Author直接插Book,SQL Server 报错The INSERT statement conflicted with the FOREIGN KEY constraint,此时需回溯检查依赖。

3.3 核心查询实现:五类高频场景的 SQL 写法与优化点

(1)单表查询:精准定位与索引意识
-- 场景:管理员查所有库存低于预警线的图书 SELECT b.Title, b.ISBN, i.Quantity, i.LowStockThreshold FROM Book b JOIN Inventory i ON b.BookID = i.BookID WHERE i.Quantity < i.LowStockThreshold; -- ✅ 正确:用 JOIN 连表,WHERE 过滤 -- ❌ 错误:SELECT * FROM Inventory WHERE Quantity < 5 —— 不知对应哪本书

优化点:在Inventory.Quantity上建非聚集索引,因该字段高频用于WHERE查询:

CREATE NONCLUSTERED INDEX IX_Inventory_Quantity ON Inventory(Quantity);
(2)多表查询:正确 JOIN 与避免笛卡尔积
-- 场景:查某顾客(C011)的所有订单及图书详情 SELECT o.OrderID, o.OrderDate, o.Status, b.Title, oi.Quantity, oi.UnitPrice FROM [Order] o JOIN OrderItem oi ON o.OrderID = oi.OrderID JOIN Book b ON oi.BookID = b.BookID WHERE o.CustomerID = 'C011' ORDER BY o.OrderDate DESC;

关键:JOIN顺序必须与依赖链一致(Order→OrderItem→Book),若写成Book JOIN OrderItem JOIN Order,SQL Server 仍能执行,但逻辑混乱,答辩时易被质疑设计思路。

(3)分组查询:聚合函数与 GROUP BY 的强制配对
-- 场景:统计各分类销量TOP3图书 SELECT c.Name AS CategoryName, b.Title, SUM(oi.Quantity) AS TotalSold FROM Book b JOIN BookCategory bc ON b.BookID = bc.BookID JOIN Category c ON bc.CategoryID = c.CategoryID JOIN OrderItem oi ON b.BookID = oi.BookID GROUP BY c.Name, b.Title ORDER BY c.Name, TotalSold DESC;

注意:GROUP BY必须包含SELECT中所有非聚合字段(c.Name,b.Title),否则报错Column 'xxx' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause。

(4)嵌套查询:EXISTS 替代 IN 的性能优势
-- 场景:查从未被购买过的图书(无任何 OrderItem 记录) -- ✅ 推荐:EXISTS(半连接,找到即停) SELECT b.BookID, b.Title FROM Book b WHERE NOT EXISTS ( SELECT 1 FROM OrderItem oi WHERE oi.BookID = b.BookID ); -- ❌ 避免:IN(需生成完整子查询结果集) -- SELECT b.BookID, b.Title FROM Book b -- WHERE b.BookID NOT IN (SELECT DISTINCT BookID FROM OrderItem); -- 若 OrderItem.BookID 有 NULL,NOT IN 永远返回空集!
(5)集合查询:UNION ALL 与 UNION 的语义区别
-- 场景:合并“库存为0”和“销量TOP5”图书列表(允许重复) SELECT 'Out of Stock' AS Source, b.Title, b.ISBN FROM Book b JOIN Inventory i ON b.BookID = i.BookID WHERE i.Quantity = 0 UNION ALL SELECT 'Top Seller' AS Source, b.Title, b.ISBN FROM Book b JOIN OrderItem oi ON b.BookID = oi.BookID GROUP BY b.BookID, b.Title, b.ISBN ORDER BY COUNT(*) DESC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY;

说明:UNION ALL不去重、不排序,性能优于UNION;此处用OFFSET...FETCH实现分页,替代低效的TOP N(当需跨页时TOP无法满足)。


4. 避坑指南:数据库设计与操作中五个最高频翻车点

做毕设最怕的不是不会写,而是写了却不知为何错。以下五条,是我带过27个数据库项目后,学生踩坑率最高的问题。每条按“现象→原因→解决”展开,全是答辩现场真实发生过的。

4.1 现象:INSERT INTO Customer报错Violation of PRIMARY KEY constraint,但明明没输重复CustomerID

  • 原因:CustomerID定义为CHAR(10),你输入'C011'(长度4),SQL Server 会自动右补6个空格变成'C011 '(长度10)。下次再输'C011',系统认为'C011 '≠'C011 '?不,它认为相等,因CHAR类型比较时自动右补空格。但若某次手误输'C011 '(带1个空格),则'C011 '≠'C011 ',看似不同实则冲突。
  • 解决:
    ✅ 立即改字段类型:ALTER TABLE Customer ALTER COLUMN CustomerID VARCHAR(10) NOT NULL;
    ✅ 后续所有INSERT用VARCHAR语义,不再补空格;
    ✅ 在 SSMS 中查看实际存储值:SELECT CustomerID, LEN(CustomerID) FROM Customer,确认长度。

4.2 现象:SELECT * FROM Order返回空,但SELECT * FROM [Order]正常

  • 原因:Order是 SQL Server 保留关键字(ORDER BY的ORDER)。建表时用方括号[Order]可创建,但查询时若不加括号,SQL Server 解析为语法错误。
  • 解决:
    ✅ 所有涉及Order、User、Index等关键字的表名,查询时必须加方括号;
    ✅ 更彻底方案:重命名表为SalesOrder或CustomerOrder,一劳永逸;
    ✅ 答辩演示时,提前在 SSMS 中执行SELECT * FROM [Order]并截图,避免现场手忙脚乱。

4.3 现象:UPDATE Inventory SET Quantity = Quantity - 1 WHERE BookID = 'B00000000001'执行后库存变负数

  • 原因:未加事务控制与库存校验。UPDATE直接减,若并发下单(两个用户同时买最后一本书),可能都读到Quantity=1,都减1,结果Quantity=-1。
  • 解决:
    ✅ 用事务+条件更新,确保原子性:
    BEGIN TRANSACTION; UPDATE Inventory SET Quantity = Quantity - 1 WHERE BookID = 'B00000000001' AND Quantity >= 1; IF @@ROWCOUNT = 0 ROLLBACK TRANSACTION; -- 库存不足,回滚 ELSE COMMIT TRANSACTION;
    ✅ 答辩时可补充:“高并发场景需加行锁,此处为简化演示,实际应结合应用层库存预占”。

4.4 现象:SELECT b.Title, a.Name FROM Book b, Author a WHERE b.AuthorID = a.AuthorID能运行,但老师说“这是老写法,不推荐”

  • 原因:此为 SQL-89 风格隐式 JOIN,易引发笛卡尔积(若WHERE条件漏写,全表交叉)。SQL-92 显式JOIN语法更清晰、更安全。
  • 解决:
    ✅ 所有新写查询,强制用FROM Book b JOIN Author a ON b.AuthorID = a.AuthorID;
    ✅ 在报告中注明:“采用 ANSI SQL-92 标准,提升可读性与可维护性”;
    ✅ 若老师追问,可答:“隐式 JOIN 在复杂查询中易遗漏关联条件,显式 JOIN 将关联逻辑前置,降低出错概率”。

4.5 现象:INSERT INTO Book VALUES ('B00000000001', ...)成功,但SELECT * FROM Book WHERE ISBN = '9787302147510'查不到

  • 原因:ISBN字段定义为VARCHAR(20),但你插入时用了全角字符(如‘9787302147510’),或前后有不可见空格(复制粘贴导致)。
  • 解决:
    ✅ 插入前清洗数据:INSERT INTO Book VALUES ('B00000000001', ..., LTRIM(RTRIM('9787302147510')), ...);
    ✅ 建唯一索引时指定COLLATE Latin1_General_BIN(二进制比较),避免全角/半角混淆:
    CREATE UNIQUE INDEX UX_Book_ISBN ON Book(ISBN COLLATE Latin1_General_BIN);
    ✅ 答辩演示时,用SELECT ISBN, DATALENGTH(ISBN) FROM Book展示实际字节长度,证明无隐藏字符。

5. 系统验收与答辩准备:一份可直接打印的验收清单与答辩话术

验收不是走过场,而是验证你的设计能否真正支撑业务。我给学生做的验收清单,从来不是“功能是否实现”,而是“业务场景是否闭环”。以下这份清单,你打印出来,一项项打钩,答辩前夜再过一遍,心里就有底了。

5.1 功能验收清单:12项必测场景(附 SQL 验证语句)

序号验收场景验证 SQL(执行后应返回预期结果)是否通过
1新增图书成功INSERT INTO Book VALUES ('B99999999999', '测试书', '9780000000000', '2024-01-01', 99.00, 'A0000001', 'P0000001', 'A'); SELECT * FROM Book WHERE BookID='B99999999999';☐
2图书ISBN唯一性INSERT INTO Book VALUES ('B99999999998', '重复ISBN书', '9787302147510', ...);→ 应报错Cannot insert duplicate key☐
3库存预警触发SELECT * FROM Book b JOIN Inventory i ON b.BookID=i.BookID WHERE i.Quantity < i.LowStockThreshold;→ 至少返回1条(如B00000000010)☐
4订单总金额自动计算SELECT TotalAmount FROM [Order] WHERE OrderID='O20240000000001';→ 应等于39.00+69.00=108.00(非原文档107.00)☐
5同一订单不允许多次添加同书INSERT INTO OrderItem VALUES ('OI99999999', 'O20240000000001', 'B00000000001', 1, 39.00);→ 应报错Cannot insert duplicate key in object 'OrderItem'☐
6顾客手机号唯一INSERT INTO Customer VALUES ('C999', '测试', 'M', 25, 'test@163.com', '17728782688', '测试地址');→ 应报错Cannot insert duplicate key in object 'Customer'☐
7一书多类查询SELECT b.Title, c.Name FROM Book b JOIN BookCategory bc ON b.BookID=bc.BookID JOIN Category c ON bc.CategoryID=c.CategoryID WHERE b.BookID='B00000000002';→ 应返回2条(数据结构、数据库原理)☐
8销售员查今日销量SELECT b.Title, SUM(oi.Quantity) FROM [Order] o JOIN OrderItem oi ON o.OrderID=oi.OrderID JOIN Book b ON oi.BookID=b.BookID WHERE CAST(o.OrderDate AS DATE) = '2024-03-10' GROUP BY b.Title;☐
9库存扣减后不为负UPDATE Inventory SET Quantity = Quantity - 1 WHERE BookID='B00000000010'; SELECT Quantity FROM Inventory WHERE BookID='B00000000010';→ 应为-1?不,应先加AND Quantity>=1条件(见4.3)☐
10下架图书不显示在搜索结果`UPDATE Book SET Status='I' WHERE BookID='B0000

本文还有配套的精品资源,点击获取