news 2026/7/6 22:25:03

SQL 实战:从0到1构建图书借阅系统,完成5个核心业务查询

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SQL 实战:从0到1构建图书借阅系统,完成5个核心业务查询

SQL 实战:从0到1构建图书借阅系统,完成5个核心业务查询

1. 系统架构设计与数据准备

图书借阅系统的核心在于构建合理的数据库结构并填充真实可用的测试数据。我们先从基础表结构开始,逐步构建完整的业务模型。

1.1 数据库表设计

图书借阅系统通常包含以下核心表:

-- 创建数据库 CREATE DATABASE library_db; USE library_db; -- 图书表 CREATE TABLE books ( book_id INT PRIMARY KEY, title VARCHAR(255) NOT NULL, author VARCHAR(100) NOT NULL, publisher VARCHAR(100) NOT NULL, publish_date DATE NOT NULL, isbn VARCHAR(20) UNIQUE, total_copies INT DEFAULT 1, available_copies INT DEFAULT 1, CHECK (available_copies <= total_copies) ); -- 读者表 CREATE TABLE readers ( reader_id INT PRIMARY KEY, name VARCHAR(50) NOT NULL, email VARCHAR(100) UNIQUE, phone VARCHAR(20), membership_date DATE NOT NULL, max_borrow_limit INT DEFAULT 5 ); -- 借阅记录表 CREATE TABLE borrow_records ( record_id INT AUTO_INCREMENT PRIMARY KEY, book_id INT NOT NULL, reader_id INT NOT NULL, borrow_date DATE NOT NULL, due_date DATE NOT NULL, return_date DATE, status ENUM('借出', '已还', '逾期') DEFAULT '借出', FOREIGN KEY (book_id) REFERENCES books(book_id), FOREIGN KEY (reader_id) REFERENCES readers(reader_id), CHECK (due_date > borrow_date), CHECK (return_date IS NULL OR return_date >= borrow_date) );

1.2 模拟数据插入

-- 插入图书数据 INSERT INTO books VALUES (1, '数据库系统概念', 'Abraham Silberschatz', '机械工业出版社', '2019-01-15', '9787111634315', 10, 8), (2, 'SQL必知必会', 'Ben Forta', '人民邮电出版社', '2020-05-01', '9787115517044', 5, 3), (3, '高性能MySQL', 'Baron Schwartz', '电子工业出版社', '2018-11-01', '9787121384101', 8, 6), (4, 'Python编程:从入门到实践', 'Eric Matthes', '人民邮电出版社', '2020-07-01', '9787115546081', 15, 12), (5, '算法导论', 'Thomas H.Cormen', '机械工业出版社', '2013-01-01', '9787111407010', 7, 4); -- 插入读者数据 INSERT INTO readers VALUES (101, '张三', 'zhangsan@example.com', '13800138001', '2022-01-10', 5), (102, '李四', 'lisi@example.com', '13800138002', '2022-02-15', 5), (103, '王五', 'wangwu@example.com', '13800138003', '2022-03-20', 3), (104, '赵六', 'zhaoliu@example.com', '13800138004', '2022-04-25', 5); -- 插入借阅记录 INSERT INTO borrow_records (book_id, reader_id, borrow_date, due_date, return_date, status) VALUES (1, 101, '2023-01-05', '2023-02-05', '2023-01-20', '已还'), (2, 101, '2023-01-10', '2023-02-10', NULL, '借出'), (3, 102, '2023-01-15', '2023-02-15', '2023-02-10', '已还'), (1, 103, '2023-01-20', '2023-02-20', NULL, '逾期'), (4, 104, '2023-01-25', '2023-02-25', '2023-02-20', '已还');

2. 核心业务查询实现

2.1 查询读者当前借阅情况

SELECT r.reader_id, r.name, b.title, br.borrow_date, br.due_date, DATEDIFF(CURRENT_DATE, br.due_date) AS overdue_days FROM readers r JOIN borrow_records br ON r.reader_id = br.reader_id JOIN books b ON br.book_id = b.book_id WHERE br.status = '借出' AND r.reader_id = 101;

执行结果示例

reader_idnametitleborrow_datedue_dateoverdue_days
101张三SQL必知必会2023-01-102023-02-10-5

2.2 统计每月借阅量Top 5的图书

SELECT b.book_id, b.title, COUNT(*) AS borrow_count, MONTH(br.borrow_date) AS month FROM books b JOIN borrow_records br ON b.book_id = br.book_id WHERE YEAR(br.borrow_date) = YEAR(CURRENT_DATE) GROUP BY b.book_id, b.title, MONTH(br.borrow_date) ORDER BY month, borrow_count DESC LIMIT 5;

执行结果示例

book_idtitleborrow_countmonth
1数据库系统概念21
2SQL必知必会11
3高性能MySQL11
4Python编程11

2.3 查询逾期未还的图书及读者信息

SELECT r.reader_id, r.name, r.email, b.title, br.borrow_date, br.due_date, DATEDIFF(CURRENT_DATE, br.due_date) AS overdue_days FROM borrow_records br JOIN readers r ON br.reader_id = r.reader_id JOIN books b ON br.book_id = b.book_id WHERE br.status = '借出' AND br.due_date < CURRENT_DATE;

执行结果示例

reader_idnameemailtitleborrow_datedue_dateoverdue_days
103王五wangwu@example.com数据库系统概念2023-01-202023-02-2015

2.4 图书借阅热度分析

SELECT b.book_id, b.title, b.author, COUNT(br.record_id) AS total_borrows, b.available_copies, CONCAT(ROUND(COUNT(br.record_id) / (SELECT COUNT(*) FROM borrow_records) * 100, 2), '%') AS borrow_percentage FROM books b LEFT JOIN borrow_records br ON b.book_id = br.book_id GROUP BY b.book_id, b.title, b.author, b.available_copies ORDER BY total_borrows DESC;

执行结果示例

book_idtitleauthortotal_borrowsavailable_copiesborrow_percentage
1数据库系统概念Abraham Silberschatz2840.00%
2SQL必知必会Ben Forta1320.00%
3高性能MySQLBaron Schwartz1620.00%
4Python编程Eric Matthes11220.00%

2.5 读者借阅行为分析

SELECT r.reader_id, r.name, COUNT(br.record_id) AS total_borrows, SUM(CASE WHEN br.status = '已还' THEN 1 ELSE 0 END) AS returned_books, SUM(CASE WHEN br.status = '借出' AND br.due_date >= CURRENT_DATE THEN 1 ELSE 0 END) AS current_borrows, SUM(CASE WHEN br.status = '借出' AND br.due_date < CURRENT_DATE THEN 1 ELSE 0 END) AS overdue_books, MAX(br.borrow_date) AS last_borrow_date FROM readers r LEFT JOIN borrow_records br ON r.reader_id = br.reader_id GROUP BY r.reader_id, r.name ORDER BY total_borrows DESC;

执行结果示例

reader_idnametotal_borrowsreturned_bookscurrent_borrowsoverdue_bookslast_borrow_date
101张三21102023-01-10
102李四11002023-01-15
103王五10012023-01-20
104赵六11002023-01-25

3. 性能优化与索引建议

3.1 关键索引设计

-- 为频繁查询的字段创建索引 CREATE INDEX idx_borrow_reader ON borrow_records(reader_id); CREATE INDEX idx_borrow_book ON borrow_records(book_id); CREATE INDEX idx_borrow_dates ON borrow_records(borrow_date, due_date, return_date); CREATE INDEX idx_reader_email ON readers(email); -- 复合索引优化热门查询 CREATE INDEX idx_book_popularity ON books(title, author);

3.2 查询优化技巧

  1. 避免全表扫描:确保WHERE条件使用索引列
  2. 合理使用JOIN:小表驱动大表原则
  3. 限制返回数据量:使用LIMIT分页
  4. **避免SELECT ***:只查询需要的列

优化示例

-- 优化前 SELECT * FROM borrow_records WHERE reader_id = 101; -- 优化后 SELECT br.record_id, b.title, br.borrow_date, br.due_date FROM borrow_records br JOIN books b ON br.book_id = b.book_id WHERE br.reader_id = 101;

4. 扩展功能实现

4.1 图书预约功能

-- 新增预约表 CREATE TABLE reservations ( reservation_id INT AUTO_INCREMENT PRIMARY KEY, book_id INT NOT NULL, reader_id INT NOT NULL, reserve_date DATETIME DEFAULT CURRENT_TIMESTAMP, status ENUM('等待', '可借', '取消') DEFAULT '等待', FOREIGN KEY (book_id) REFERENCES books(book_id), FOREIGN KEY (reader_id) REFERENCES readers(reader_id) ); -- 预约存储过程 DELIMITER // CREATE PROCEDURE reserve_book( IN p_book_id INT, IN p_reader_id INT, OUT p_result VARCHAR(100) ) BEGIN DECLARE v_available INT; -- 检查图书是否可借 SELECT available_copies INTO v_available FROM books WHERE book_id = p_book_id; IF v_available > 0 THEN SET p_result = '图书可直接借阅,无需预约'; ELSE -- 检查是否已有预约 IF NOT EXISTS (SELECT 1 FROM reservations WHERE book_id = p_book_id AND reader_id = p_reader_id AND status = '等待') THEN INSERT INTO reservations (book_id, reader_id) VALUES (p_book_id, p_reader_id); SET p_result = '预约成功'; ELSE SET p_result = '您已预约过该图书'; END IF; END IF; END // DELIMITER ;

4.2 自动逾期处理

-- 逾期处理存储过程 DELIMITER // CREATE PROCEDURE process_overdue_records() BEGIN -- 更新逾期状态 UPDATE borrow_records SET status = '逾期' WHERE status = '借出' AND due_date < CURRENT_DATE; -- 记录逾期通知 INSERT INTO notifications (reader_id, message, create_date) SELECT br.reader_id, CONCAT('您借阅的图书《', b.title, '》已逾期,请尽快归还'), CURRENT_DATE FROM borrow_records br JOIN books b ON br.book_id = b.book_id WHERE br.status = '逾期' AND br.due_date = DATE_SUB(CURRENT_DATE, INTERVAL 1 DAY); END // DELIMITER ;

5. 系统安全与维护

5.1 数据备份策略

-- 创建备份表 CREATE TABLE books_backup LIKE books; INSERT INTO books_backup SELECT * FROM books; -- 定期备份脚本示例 DELIMITER // CREATE PROCEDURE daily_backup() BEGIN DECLARE backup_date VARCHAR(20); SET backup_date = DATE_FORMAT(NOW(), '%Y%m%d'); SET @sql = CONCAT('CREATE TABLE borrow_records_backup_', backup_date, ' LIKE borrow_records'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql = CONCAT('INSERT INTO borrow_records_backup_', backup_date, ' SELECT * FROM borrow_records'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END // DELIMITER ;

5.2 权限管理

-- 创建不同角色用户 CREATE USER 'library_admin'@'localhost' IDENTIFIED BY 'Admin@123'; CREATE USER 'library_staff'@'localhost' IDENTIFIED BY 'Staff@123'; CREATE USER 'library_reader'@'localhost' IDENTIFIED BY 'Reader@123'; -- 分配权限 GRANT ALL PRIVILEGES ON library_db.* TO 'library_admin'@'localhost'; GRANT SELECT, INSERT, UPDATE ON library_db.books TO 'library_staff'@'localhost'; GRANT SELECT, INSERT, UPDATE ON library_db.borrow_records TO 'library_staff'@'localhost'; GRANT SELECT ON library_db.books TO 'library_reader'@'localhost'; GRANT SELECT ON library_db.readers TO 'library_reader'@'localhost' WITH GRANT OPTION;
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/6 22:21:59

Sidecar模式加速单体应用开发:构建、调试与发布优化实战

1. 项目概述&#xff1a;这不是一辆摩托车&#xff0c;而是一台“侧斗加速器”“Beyond Motorcycles: How Sidecars Boost Dev Speed”——这个标题乍看像一篇摩托车文化杂谈&#xff0c;实则是个极具迷惑性的技术隐喻。它根本不是讲哈雷戴维森或边三轮越野&#xff0c;而是在软…

作者头像 李华
网站建设 2026/7/6 22:21:49

KMeans 聚类评估指标详解:从原理到 sklearn 3 种方法实现

KMeans 聚类评估指标&#xff1a;从数学原理到工程实践的三维透视1. 聚类评估的本质与挑战当我们将小麦种子数据集输入KMeans算法时&#xff0c;那些看似神秘的评估指标背后&#xff0c;其实隐藏着数据科学家必须理解的数学语言。不同于监督学习有明确的标签作为评判标准&#…

作者头像 李华
网站建设 2026/7/6 22:20:32

RW-RL数据集架构解析:失败数据如何重塑机器人强化学习

RW-RL数据集架构解析&#xff1a;失败数据如何重塑机器人强化学习2026年6月29日&#xff0c;均普智能机器人创新中心联合博登智能、上海交通大学MINT实验室正式开源RW-RL-Dataset&#xff0c;这是全球首个面向真实机器人强化学习的大规模数据集。业内专业数据平台对此次开源事件…

作者头像 李华
网站建设 2026/7/6 22:20:04

GE/西门子/联影CT:4大品牌水模体模规格与240-450mm FOV适配指南

GE/西门子/联影CT&#xff1a;4大品牌水模体模规格与240-450mm FOV适配指南 在医疗影像诊断领域&#xff0c;CT设备的精准度直接关系到临床诊断的可靠性。而水模和体模作为CT设备校准的核心工具&#xff0c;其规格选择与设备FOV&#xff08;Field of View&#xff0c;视野&…

作者头像 李华
网站建设 2026/7/6 22:19:52

TongWeb 8.0 重部署 3 大陷阱:从 ‘instance stopped‘ 到 Metaspace 溢出的完整链路

TongWeb 8.0 重部署全链路故障诊断手册&#xff1a;从幽灵线程到元数据泄漏的工程实践当企业级Java应用在TongWeb应用服务器上经历多次热部署时&#xff0c;运维团队往往会遭遇一系列看似孤立却实际存在因果链的异常现象。本文将揭示从线程未释放、类加载器泄漏到Metaspace溢出…

作者头像 李华
网站建设 2026/7/6 22:19:00

Python空列表底层原理与工程实践指南

1. 为什么一个空列表值得写上万字&#xff1f;——从“[]”开始的Python底层真相你有没有在调试时盯着一行if my_list:发呆&#xff0c;心里默念“这到底判的是True还是False”&#xff1f;有没有在函数里传入[]却意外触发了某个分支&#xff0c;而文档里只轻描淡写写着“接受序…

作者头像 李华