239 lines
15 KiB
SQL
239 lines
15 KiB
SQL
SET search_path TO library, public;
|
||
|
||
-- 清理可能存在的旧数据(可选,测试时方便重跑)
|
||
-- 请注意,CASCADE 会删除关联数据,请谨慎在生产环境使用
|
||
-- DELETE FROM fines;
|
||
-- DELETE FROM reviews;
|
||
-- DELETE FROM reservations;
|
||
-- DELETE FROM borrow_records;
|
||
-- DELETE FROM admins;
|
||
-- DELETE FROM students;
|
||
-- DELETE FROM books;
|
||
-- DELETE FROM system_settings WHERE setting_key NOT IN ('fine_per_day', 'freeze_threshold', 'max_borrow_default'); -- 保留核心设置
|
||
|
||
-- 0. 系统参数 (你已插入,这里可以补充更多,如果需要)
|
||
INSERT INTO system_settings(setting_key, setting_value) VALUES
|
||
('max_renew_times', '2'), -- 最大续借次数
|
||
('borrow_duration_days', '30'), -- 默认借阅时长(天)
|
||
('reservation_expiry_days', '3'), -- 预约保留天数
|
||
('admin_default_password_hash', 'xxxx'); -- 示例:管理员默认密码哈希
|
||
-- ON CONFLICT (setting_key) DO UPDATE SET setting_value = EXCLUDED.setting_value; -- 如果要允许更新
|
||
|
||
-- 1. 管理员信息 (Admins)
|
||
INSERT INTO admins (emp_no, name, position, phone, privilege_lv) VALUES
|
||
('A001', '张管理', '馆长', '13800138000', 0), -- 最高权限
|
||
('A002', '李协助', '图书管理员', '13900139000', 1),
|
||
('A003', '王登记', '流通部职员', '13700137000', 2);
|
||
|
||
-- 2. 图书信息 (Books)
|
||
-- 注意: available_copies 初始设为 total_copies,后续借阅会通过触发器减少
|
||
INSERT INTO books (isbn, title, authors, publisher, publish_date, price, classification_no, location, total_copies, available_copies, status, description, cover_url) VALUES
|
||
('9787111624927', '深入理解计算机系统', ARRAY['Randal E. Bryant', 'David R. O''Hallaron'], '机械工业出版社', '2019-05-01', 139.00, 'TP301', 'A区2架3层', 10, 10, 'normal', '计算机系统的经典之作。', 'http://example.com/cover1.jpg'),
|
||
('9787030598007', '数学之美', ARRAY['吴军'], '科学出版社', '2020-01-01', 68.00, 'O1', 'B区1架1层', 15, 15, 'normal', '通俗易懂的数学科普读物。', 'http://example.com/cover2.jpg'),
|
||
('9787544270878', '百年孤独', ARRAY['加西亚·马尔克斯'], '南海出版公司', '2011-06-01', 39.50, 'I775.45', 'C区5架2层', 8, 8, 'normal', '魔幻现实主义文学的代表作。', 'http://example.com/cover3.jpg'),
|
||
('9787115478850', 'Python编程:从入门到实践', ARRAY['Eric Matthes'], '人民邮电出版社', '2018-03-01', 89.00, 'TP312PY', 'A区3架1层', 12, 12, 'normal', 'Python入门畅销书。', 'http://example.com/cover4.jpg'),
|
||
('9787508647009', '人类简史:从动物到上帝', ARRAY['尤瓦尔·赫拉利'], '中信出版社', '2014-11-01', 68.00, 'K02', 'D区1架1层', 20, 20, 'normal', '一部宏大的人类发展史。', 'http://example.com/cover5.jpg'),
|
||
('9787532767406', '追风筝的人', ARRAY['卡勒德·胡赛尼'], '上海人民出版社', '2006-05-01', 29.00, 'I712.45', 'C区4架3层', 7, 7, 'normal', '关于爱、友谊、背叛和救赎的故事。', 'http://example.com/cover6.jpg'),
|
||
('9787121362308', 'Java核心技术 卷I', ARRAY['Cay S. Horstmann'], '电子工业出版社', '2019-06-01', 128.00, 'TP312JA', 'A区3架2层', 5, 0, 'normal', 'Java经典教材,目前全部被借出,用于测试预约。', 'http://example.com/cover7.jpg'), -- 特意设置 available_copies 为 0
|
||
('9787208159659', '三体全集', ARRAY['刘慈欣'], '重庆出版社', '2019-01-01', 168.00, 'I247.5', 'C区6架1层', 3, 3, 'damaged', '科幻巨作,其中一本有损坏。', 'http://example.com/cover8.jpg'),
|
||
('9787559620187', '明朝那些事儿 (套装全7册)', ARRAY['当年明月'], '北京联合出版公司', '2017-08-01', 258.00, 'K248', 'D区2架1层', 6, 6, 'normal', '通俗易懂的明史。', 'http://example.com/cover9.jpg'),
|
||
('9787111600815', '算法导论 (原书第3版)', ARRAY['Thomas H. Cormen'], '机械工业出版社', '2012-12-01', 128.00, 'TP301.6', 'A区2架4层', 9, 9, 'normal', '算法领域的圣经。', 'http://example.com/cover10.jpg'),
|
||
('9780132350884', 'Clean Code', ARRAY['Robert C. Martin'], 'Prentice Hall', '2008-08-01', 50.00, 'TP311.1', 'A区1架5层', 4, 4, 'removed', '一本已下架的书,测试状态。', 'http://example.com/cover11.jpg');
|
||
|
||
|
||
-- 3. 学生信息 (Students)
|
||
-- max_borrow 使用默认值(通过 get_setting_int('max_borrow_default') 获取,即10)
|
||
-- current_borrow 初始为0,会由触发器更新
|
||
INSERT INTO students (stu_no, name, gender, department, major, grade, class, phone, email, account_status) VALUES
|
||
('S2023001', '张三', 'M', '计算机学院', '软件工程', '2023', '01班', '13512345671', 'zhangsan@example.com', 'active'),
|
||
('S2023002', '李四', 'F', '计算机学院', '人工智能', '2023', '02班', '13512345672', 'lisi@example.com', 'active'),
|
||
('S2022003', '王五', 'M', '外国语学院', '英语', '2022', '01班', '13512345673', 'wangwu@example.com', 'active'),
|
||
('S2021004', '赵六', 'F', '经济管理学院', '工商管理', '2021', '03班', '13512345674', 'zhaoliu@example.com', 'active'),
|
||
('S2023005', '孙七', 'M', '计算机学院', '软件工程', '2023', '01班', '13512345675', 'sunqi@example.com', 'reported'), -- 测试挂失状态
|
||
('S2022006', '周八', 'F', '人文学院', '历史学', '2022', '02班', '13512345676', 'zhouba@example.com', 'active'),
|
||
('S2021007', '吴九', 'M', '理学院', '数学与应用数学', '2021', '01班', '13512345677', 'wujiu@example.com', 'active'),
|
||
('S2023008', '郑十', 'F', '计算机学院', '网络工程', '2023', '03班', '13512345678', 'zhengshi@example.com', 'active');
|
||
|
||
-- 修改一个学生的 max_borrow,测试非默认值
|
||
UPDATE students SET max_borrow = 15 WHERE stu_no = 'S2023001';
|
||
UPDATE students SET max_borrow = 5 WHERE stu_no = 'S2021004'; -- 用于测试借阅上限
|
||
|
||
-- 4. 借阅记录 (Borrow Records)
|
||
-- book_id 和 student_id 需要引用已存在的 ID
|
||
-- due_date = borrow_date + (SELECT setting_value::int FROM system_settings WHERE setting_key = 'borrow_duration_days')
|
||
-- fine_amount 初始为0, 逾期归还将由触发器在 fines 表中记录罚款
|
||
-- 触发器 trg_sync_book_student 会在每次插入/更新/删除后执行
|
||
|
||
-- 获取 book_id 和 student_id 的示例 (实际使用时,你可能需要根据书名/学号查询得到)
|
||
-- SELECT book_id FROM books WHERE isbn = '9787111624927'; -- 1
|
||
-- SELECT student_id FROM students WHERE stu_no = 'S2023001'; -- 1
|
||
|
||
-- 借阅场景 1: 正常借出,未到期
|
||
INSERT INTO borrow_records (book_id, student_id, borrow_date, due_date, status) VALUES
|
||
(1, 1, current_date - interval '10 days', current_date - interval '10 days' + interval '30 days', 'borrowed'), -- 张三借《深入理解计算机系统》
|
||
(2, 2, current_date - interval '5 days', current_date - interval '5 days' + interval '30 days', 'borrowed'); -- 李四借《数学之美》
|
||
|
||
-- 借阅场景 2: 正常借出,今天到期
|
||
INSERT INTO borrow_records (book_id, student_id, borrow_date, due_date, status) VALUES
|
||
(3, 1, current_date - interval '30 days', current_date, 'borrowed'); -- 张三借《百年孤独》,今天到期
|
||
|
||
-- 借阅场景 3: 已逾期,未归还
|
||
INSERT INTO borrow_records (book_id, student_id, borrow_date, due_date, status) VALUES
|
||
(4, 3, current_date - interval '40 days', current_date - interval '10 days', 'overdue'); -- 王五借《Python编程》,已逾期10天
|
||
|
||
-- 借阅场景 4: 正常归还 (触发器 trg_calc_fine 不会产生罚款)
|
||
INSERT INTO borrow_records (book_id, student_id, borrow_date, due_date, return_date, status) VALUES
|
||
(5, 4, current_date - interval '20 days', current_date + interval '10 days', current_date - interval '2 days', 'returned'); -- 赵六借《人类简史》,已按时归还
|
||
|
||
-- 借阅场景 5: 逾期归还 (为了测试 trg_calc_fine,先插入为逾期,再UPDATE为归还)
|
||
-- 步骤A: 先插入一条记录,状态为 'overdue' (或者 'borrowed' 但实际已过 due_date)
|
||
INSERT INTO borrow_records (book_id, student_id, borrow_date, due_date, status)
|
||
VALUES (6, 5, current_date - interval '35 days', current_date - interval '5 days', 'overdue'); -- 孙七借《追风筝的人》
|
||
-- 记录下这条 borrow_id (假设是 6,根据实际情况调整)
|
||
-- 步骤B: 更新这条记录为 'returned',这将触发 trg_calc_fine
|
||
-- UPDATE borrow_records
|
||
-- SET status = 'returned', return_date = current_date
|
||
-- WHERE borrow_id = (SELECT borrow_id FROM borrow_records WHERE student_id=5 AND book_id=6 AND status='overdue');
|
||
-- (该update放到下面演示触发器部分)
|
||
|
||
-- 借阅场景 6: 书籍遗失
|
||
INSERT INTO borrow_records (book_id, student_id, borrow_date, due_date, status) VALUES
|
||
(9, 6, current_date - interval '15 days', current_date + interval '15 days', 'lost'); -- 周八借《明朝那些事儿》,遗失
|
||
|
||
|
||
-- 5. 图书预约 (Reservations)
|
||
-- 只能预约 available_copies = 0 的书
|
||
-- (book_id=7, 'Java核心技术 卷I', available_copies 初始为0)
|
||
INSERT INTO reservations (book_id, student_id, reserve_date, status) VALUES
|
||
(7, 1, current_date - interval '2 days', 'waiting'), -- 张三预约《Java核心技术》
|
||
(7, 2, current_date - interval '1 day', 'waiting'); -- 李四预约《Java核心技术》
|
||
|
||
-- 假设一本被预约的书有归还了,管理员将其状态改为可取
|
||
-- UPDATE reservations SET status = 'available' WHERE book_id = 7 AND student_id = 1;
|
||
|
||
-- 6. 图书评价 (Reviews)
|
||
-- 学生通常评价已借阅过的书
|
||
INSERT INTO reviews (book_id, student_id, rating, content, review_time) VALUES
|
||
(5, 4, 5, '《人类简史》这本书太棒了,视角独特,值得一读!', now() - interval '1 day'), -- 赵六评价《人类简史》
|
||
(1, 1, 4, '《深入理解计算机系统》有点难,但很有收获。', now()), -- 张三评价
|
||
(2, 2, 5, '《数学之美》让我对数学有了新的认识。', now()); -- 李四评价
|
||
|
||
-- 尝试插入重复评价(应失败,因为有UNIQUE约束)
|
||
-- INSERT INTO reviews (book_id, student_id, rating, content, review_time) VALUES
|
||
-- (5, 4, 3, '第二次评价,内容一般。', now());
|
||
|
||
-- 7. 罚款记录 (Fines)
|
||
-- 部分罚款会由 trg_calc_fine 自动生成 (当逾期借阅记录更新为 'returned' 时)
|
||
-- 手动添加一些罚款记录:
|
||
|
||
-- 罚款场景1: 图书损坏 (假设管理员A002处理)
|
||
INSERT INTO fines (student_id, amount, reason, status, issue_date, admin_id) VALUES
|
||
( (SELECT student_id FROM students WHERE stu_no = 'S2022003'), -- 王五
|
||
20.00,
|
||
'损坏图书《Python编程》(ISBN:9787115478850)',
|
||
'unpaid',
|
||
current_date - interval '1 day',
|
||
(SELECT admin_id FROM admins WHERE emp_no = 'A002')
|
||
);
|
||
|
||
-- 罚款场景2: 图书遗失 (假设管理员A002处理)
|
||
-- 对应 borrow_records 中周八遗失的《明朝那些事儿》
|
||
INSERT INTO fines (student_id, amount, reason, status, issue_date, admin_id) VALUES
|
||
( (SELECT student_id FROM students WHERE stu_no = 'S2022006'), -- 周八
|
||
(SELECT price FROM books WHERE isbn = '9787559620187'), -- 按书价赔偿
|
||
'遗失图书《明朝那些事儿》(ISBN:9787559620187)',
|
||
'unpaid',
|
||
current_date,
|
||
(SELECT admin_id FROM admins WHERE emp_no = 'A002')
|
||
);
|
||
|
||
-- 罚款场景3: 之前的逾期罚款,已缴纳
|
||
INSERT INTO fines (student_id, amount, reason, status, issue_date, admin_id) VALUES
|
||
( (SELECT student_id FROM students WHERE stu_no = 'S2021007'), -- 吴九
|
||
5.50,
|
||
'图书逾期11天 (旧记录)',
|
||
'paid',
|
||
current_date - interval '60 days',
|
||
(SELECT admin_id FROM admins WHERE emp_no = 'A003')
|
||
);
|
||
|
||
|
||
----------------------------------------------------
|
||
-- 测试触发器 trg_calc_fine 和 trg_freeze_account
|
||
----------------------------------------------------
|
||
DO $$
|
||
DECLARE
|
||
v_student_id_sunqi bigint;
|
||
v_borrow_id_sunqi bigint;
|
||
v_fine_per_day numeric;
|
||
v_days_overdue int;
|
||
v_expected_fine numeric;
|
||
BEGIN
|
||
-- 获取孙七的 student_id
|
||
SELECT student_id INTO v_student_id_sunqi FROM students WHERE stu_no = 'S2023005';
|
||
-- 获取孙七之前插入的逾期借阅记录 (book_id=6, 追风筝的人)
|
||
SELECT borrow_id INTO v_borrow_id_sunqi
|
||
FROM borrow_records
|
||
WHERE student_id = v_student_id_sunqi AND book_id = (SELECT book_id FROM books WHERE isbn='9787532767406') AND status = 'overdue';
|
||
|
||
RAISE NOTICE '孙七(ID:%)的借阅记录ID: % 将被更新为已归还。', v_student_id_sunqi, v_borrow_id_sunqi;
|
||
|
||
-- 模拟孙七归还之前逾期的书 (book_id=6, 《追风筝的人》)
|
||
-- 这将触发 trg_calc_fine
|
||
UPDATE borrow_records
|
||
SET status = 'returned', return_date = current_date
|
||
WHERE borrow_id = v_borrow_id_sunqi;
|
||
|
||
RAISE NOTICE '已更新孙七的借阅记录。现在检查 fines 表是否自动产生罚款记录...';
|
||
-- trg_calc_fine 会根据 borrow_records 中的 due_date 和 return_date 计算罚款并插入 fines 表
|
||
-- 假设罚款汇率是 0.5/天,逾期5天,罚款应为 2.50
|
||
-- (current_date - (current_date - interval '5 days')) * 0.50
|
||
SELECT setting_value::numeric INTO v_fine_per_day FROM system_settings WHERE setting_key = 'fine_per_day';
|
||
SELECT (current_date - (SELECT due_date FROM borrow_records WHERE borrow_id = v_borrow_id_sunqi)) INTO v_days_overdue;
|
||
v_expected_fine := v_days_overdue * v_fine_per_day;
|
||
RAISE NOTICE '预期罚款金额: % * % = %', v_days_overdue, v_fine_per_day, v_expected_fine;
|
||
|
||
-- 检查孙七的账户状态是否因为罚款超过阈值 (默认20) 而被冻结
|
||
-- trg_freeze_account 会在 fines 表 INSERT/UPDATE/DELETE 后触发
|
||
RAISE NOTICE '检查孙七账户是否因罚款自动冻结...';
|
||
-- 如果孙七的罚款 (例如 2.50) 没有超过 freeze_threshold (默认20.00),账户不会冻结。
|
||
-- 我们再为孙七手动添加一笔大额罚款,使其总欠款超过阈值
|
||
IF (SELECT sum(amount) FROM fines WHERE student_id = v_student_id_sunqi AND status = 'unpaid') < (SELECT setting_value::numeric FROM system_settings WHERE setting_key = 'freeze_threshold') THEN
|
||
RAISE NOTICE '孙七当前未付罚款未达冻结阈值,为其添加一笔大额罚款...';
|
||
INSERT INTO fines (student_id, amount, reason, status, issue_date, admin_id) VALUES
|
||
(v_student_id_sunqi, 25.00, '严重损坏图书赔偿', 'unpaid', current_date, (SELECT admin_id FROM admins WHERE emp_no='A001'));
|
||
RAISE NOTICE '已为孙七添加大额罚款,再次检查账户状态。';
|
||
END IF;
|
||
|
||
END $$;
|
||
|
||
-- 查询验证触发器效果
|
||
RAISE NOTICE '---------- 查询验证 ----------';
|
||
|
||
RAISE NOTICE '1. 书籍可借数量和学生当前借阅量 (应由 trg_sync_book_student 更新):';
|
||
SELECT book_id, title, total_copies, available_copies FROM books WHERE book_id <= 7;
|
||
SELECT student_id, name, max_borrow, current_borrow, account_status FROM students WHERE student_id <= 5;
|
||
|
||
RAISE NOTICE '2. 孙七 (S2023005) 的罚款记录 (应有 trg_calc_fine 生成的逾期罚款 和 手动添加的罚款):';
|
||
SELECT f.*, s.name as student_name
|
||
FROM fines f JOIN students s ON f.student_id = s.student_id
|
||
WHERE s.stu_no = 'S2023005';
|
||
|
||
RAISE NOTICE '3. 孙七 (S2023005) 的账户状态 (应由 trg_freeze_account 根据总欠款更新):';
|
||
SELECT stu_no, name, account_status, current_borrow
|
||
FROM students
|
||
WHERE stu_no = 'S2023005';
|
||
|
||
RAISE NOTICE '4. 查看热门图书视图:';
|
||
SELECT * FROM v_hot_books;
|
||
|
||
RAISE NOTICE '5. 查看院系借阅统计视图:';
|
||
SELECT * FROM v_dept_borrow_stats;
|
||
|
||
RAISE NOTICE '6. 查看逾期详情视图:';
|
||
SELECT od.*, b.title, s.name as student_name
|
||
FROM v_overdue_details od
|
||
JOIN books b ON od.book_id = b.book_id
|
||
JOIN students s ON od.student_id = s.student_id;
|
||
|
||
RAISE NOTICE '测试数据插入完毕。'; |