简介:这是一份面向古典文学研究者、中文专业师生及诗词爱好者的数据资源,提供结构完整、内容详实的诗词诗人MySQL数据库,用于支持古籍数字化分析、教学案例构建与个人学习检索。资源包含3个核心SQL文件,分别定义诗人信息表、诗词元数据表及诗词全文与注解内容表,覆盖13136位诗人与305131首诗词,数据组织规范,字段设计兼顾学术研究与应用查询需求。压缩包为ZIP格式,共3个SQL文件,总大小47.46MB,轻量易部署,可直接导入本地MySQL环境使用。已有2299人学习下载,读者可立即获得可运行的数据库结构与全量数据,无需手动整理文本,节省数据清洗时间;同时便于拓展微信小程序类前端应用、构建诗词检索系统或开展诗人风格统计分析等进阶实践。
1. 诗词诗人数据库:一个能直接导入 MySQL 的结构化古诗文资源包,解决古籍数据零散、格式混乱、字段缺失的硬伤
你是不是也试过从多个网站爬取唐诗宋词,结果发现每家字段不统一——有的带朝代没生卒年,有的有作者简介却漏了代表作,有的连诗题都用「《》」和「“”」混着标?更头疼的是,好不容易整理好 CSV,一导入 MySQL 就报错:Incorrect date value(生卒年写成“约701年—762年”)、Data too long(某首长律注释塞了2000字进 VARCHAR(255))、甚至Unknown column 'poem_content' in field list(表结构和数据列名对不上)……这不是数据问题,是缺乏一套开箱即用、字段定义严谨、MySQL 原生兼容的诗词诗人数据库。本篇讲的,就是这样一个已预建表结构、含完整索引、字段类型经实测校验、支持一键 source 导入的.sql文件包。它不是 API,不是网页爬虫脚本,而是一份可审计、可版本化、可嵌入任何本地开发环境的数据库快照。适合古籍数字化项目初期建模、教学演示用真实语料、或 NLP 任务前的数据基线准备——尤其当你需要稳定复现、拒绝玄学字段、且不想花三天调LOAD DATA INFILE编码和 NULL 处理时。
2. 数据库设计逻辑:为什么用这 4 张表 + 这些字段,而不是一张大宽表或 JSON 字段
古诗文数据天然具备多层关系:一位诗人(poets)创作多首诗(poems),一首诗可能有多个体裁标签(如「五言律诗」「边塞诗」),也可能被后人多次注解(annotations)。若强行压成单表,会导致大量冗余(诗人信息重复存储)、更新异常(改个诗人字号要扫全表)、以及无法高效查询(比如“找所有盛唐时期写过边塞诗的诗人”需多条件跨列扫描)。我们采用符合第三范式的四表结构,兼顾查询效率与维护性。下面逐表说明设计依据与字段选型理由。
2.1poets表:诗人元信息的最小完备集
诗人表不追求百科全书式覆盖,而是聚焦可验证、可索引、可关联的核心字段。例如:
birth_year和death_year用SMALLINT而非VARCHAR,是因为绝大多数诗人年代在 -500 到 1900 年间,SMALLINT范围(-32768 ~ 32767)完全够用,且支持数值比较(如WHERE birth_year BETWEEN 618 AND 907查唐代诗人),避免字符串解析开销;dynasty用ENUM('先秦','汉','魏晋','南北朝','隋','唐','五代','宋','辽','金','元','明','清'),而非VARCHAR,既防录入脏数据(如误输“唐朝”“大唐”“Tang”),又节省存储(ENUM 实际存整数索引);bio_summary设为TEXT而非VARCHAR(2000),因诗人小传长度差异极大(陶渊明传可能 300 字,而《全宋诗》某冷门诗人小传超 1500 字),TEXT无长度硬限,且 MySQL 8.0+ 对TEXT索引优化已足够支撑FULLTEXT检索。
CREATE TABLE `poets` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(100) NOT NULL COMMENT '诗人本名,如“李白”', `courtesy_name` VARCHAR(100) DEFAULT NULL COMMENT '字,如“太白”', `hao` VARCHAR(100) DEFAULT NULL COMMENT '号,如“青莲居士”', `birth_year` SMALLINT DEFAULT NULL COMMENT '出生年份,公元纪年,如701', `death_year` SMALLINT DEFAULT NULL COMMENT '去世年份,如762', `dynasty` ENUM('先秦','汉','魏晋','南北朝','隋','唐','五代','宋','辽','金','元','明','清') NOT NULL, `bio_summary` TEXT COMMENT '生平简述,含籍贯、仕途、文学地位等', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX `idx_dynasty_birth` (`dynasty`, `birth_year`), FULLTEXT KEY `ft_bio` (`bio_summary`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;提示:
FULLTEXT索引仅在InnoDB引擎下支持自然语言模式搜索,比LIKE '%xxx%'快一个数量级。但注意——它默认忽略少于 4 字符的词(如“杜甫”会被切为“杜”“甫”,而“甫”因太短被忽略),实际使用需配合innodb_ft_min_token_size=2配置(见第 5 章)。
2.2poems表:诗作主体与结构化解析字段
诗作表的关键设计在于分离“内容”与“元数据”。content字段存纯文本(含换行符\n),不嵌 HTML 或 Markdown;所有结构信息(句数、字数、押韵位置)由计算字段或关联表承载。这样既保证内容纯净,又便于后续 NLP 处理(如分句、词性标注无需先清洗标签)。
line_count和char_count是预计算字段,非实时LENGTH(content),因为古诗字数统计有规则(如“之乎者也”算虚词不计入正文字数?本库按通行《全唐诗》校勘本计,含所有可见字符);rhyme_scheme用VARCHAR(20)存如ABAB、AABB,而非 JSON,因押韵模式高度结构化且枚举有限,字符串匹配比 JSON 解析快 3~5 倍;tags字段弃用,改用关联表poem_tags(见 2.4 节),避免tags字段出现“山水,隐逸,五律”这类逗号分隔导致WHERE tags LIKE '%隐逸%'无法走索引。
CREATE TABLE `poems` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `title` VARCHAR(200) NOT NULL COMMENT '诗题,如“望庐山瀑布”', `content` TEXT NOT NULL COMMENT '正文,每句一行,句末无标点,如“日照香炉生紫烟\n遥看瀑布挂前川”', `line_count` TINYINT UNSIGNED NOT NULL COMMENT '句数,如4(绝句)、8(律诗)', `char_count` SMALLINT UNSIGNED NOT NULL COMMENT '总字数(不含空格换行)', `rhyme_scheme` VARCHAR(20) DEFAULT NULL COMMENT '押韵格式,如ABAB、AABB', `poet_id` INT UNSIGNED NOT NULL COMMENT '关联poets.id', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX `idx_poet_id` (`poet_id`), INDEX `idx_line_char` (`line_count`, `char_count`), FULLTEXT KEY `ft_content_title` (`content`, `title`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;2.3poem_tags关联表:解决多对多标签的标准化管理
古诗标签(体裁、题材、风格)必须独立建模。若把标签塞进poems表,会违反第一范式(字段含重复组),且无法高效查询“所有带『边塞』标签的诗”。本库采用经典三元组设计:poem_id+tag_id+tag_type(区分是体裁、题材还是风格),并建立联合唯一索引防重复绑定。
CREATE TABLE `poem_tags` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `poem_id` INT UNSIGNED NOT NULL COMMENT '关联poems.id', `tag_id` INT UNSIGNED NOT NULL COMMENT '关联tags.id', `tag_type` ENUM('genre','theme','style') NOT NULL COMMENT '标签类型', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY `uk_poem_tag_type` (`poem_id`, `tag_id`, `tag_type`), INDEX `idx_tag_type` (`tag_type`, `tag_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;2.4tags标签主表:预置权威分类体系,拒绝自由录入
tags表不开放用户增删,而是内置经文献考证的 127 个标准标签(截至 2024 年《中国古典诗歌分类辞典》修订版)。例如体裁类含「五言古诗」「七言歌行」「乐府旧题」;题材类含「咏史怀古」「送别酬唱」「田园山水」;风格类含「沉郁顿挫」「清新飘逸」「雄浑悲壮」。每个标签有category字段标识归属('genre'/'theme'/'style'),确保poem_tags.tag_type与之严格对齐。
INSERT INTO `tags` (`name`, `category`, `description`) VALUES ('五言古诗', 'genre', '每句五字,不拘对仗平仄,篇幅自由'), ('边塞诗', 'theme', '以边疆战事、军旅生活、异域风光为题材'), ('沉郁顿挫', 'style', '杜甫诗风,情感深沉,节奏抑扬'); -- 共127条,此处仅示例注意:
poem_tags表的UNIQUE KEY uk_poem_tag_type是强约束。若脚本重复执行 INSERT,会触发Duplicate entry错误而非静默跳过——这是故意设计,逼你在导入前做去重,避免脏数据累积。
3. MySQL 文件结构解析:.sql文件里藏了哪些关键段落,如何读懂并安全修改
拿到的shici_database_v2.3.sql是一个标准 MySQL dump 文件,但并非简单mysqldump输出。它经过人工精修,包含 5 类必需段落。理解每段作用,才能安全定制(如删减字段、调整字符集、适配低版本 MySQL)。
3.1 文件头:字符集与兼容性声明(必读!)
文件开头明确声明所用字符集与 SQL 模式,这是导入不乱码的前提:
-- shici_database_v2.3.sql -- MySQL 8.0+ recommended; for 5.7, see notes below SET NAMES utf8mb4; SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00";SET NAMES utf8mb4:强制客户端通信用utf8mb4,支持 emoji 及生僻汉字(如「䶮」「龘」);SQL_MODE = "NO_AUTO_VALUE_ON_ZERO":关闭AUTO_INCREMENT字段插入0时自增的危险行为,避免误删主键;- 若你用 MySQL 5.7,需手动注释掉
utf8mb4_0900_as_cs排序规则(5.7 不支持),改为utf8mb4_unicode_ci(见第 5 章避坑)。
3.2 表创建段:带注释的 DDL,字段含义一目了然
每张表CREATE TABLE语句后紧跟COMMENT,说明字段业务含义。例如poems.content的注释强调“每句一行,句末无标点”,这直接决定你后续用 Python 读取时是否要split('\n')—— 是的,必须这样切,因为换行符是结构标记,不是排版符号。
3.3 数据插入段:INSERT INTO ... VALUES的批量写法与性能优化
数据非单条INSERT,而是每 1000 行合并为一条(MySQL 8.0 默认max_allowed_packet=64M下安全):
INSERT INTO `poets` (`name`, `courtesy_name`, `hao`, `birth_year`, `death_year`, `dynasty`, `bio_summary`) VALUES ('李白', '太白', '青莲居士', 701, 762, '唐', '字太白,号青莲居士……'), ('杜甫', '子美', '少陵野老', 712, 770, '唐', '字子美,自号少陵野老……'), -- 后续998行 ('王维', '摩诘', '摩诘居士', 699, 761, '唐', '字摩诘,号摩诘居士……');- 优势:比单条插入快 10~50 倍(减少网络往返与日志刷盘);
- 注意:若中途失败,需从上一个
INSERT开始重跑,故文件内INSERT语句按逻辑块分隔(如-- poets data、-- poems data)。
3.4 索引与外键段:显式创建,而非依赖CREATE TABLE内联
索引单独CREATE INDEX,而非写在CREATE TABLE里,原因有二:
- 方便禁用/重建(如导入时先
DROP INDEX,导完再CREATE,提速 3 倍); - 外键约束在
INSERT前禁用,避免逐行检查拖慢速度:
-- 导入前禁用外键检查 SET FOREIGN_KEY_CHECKS = 0; -- 导入后启用 SET FOREIGN_KEY_CHECKS = 1;你的.sql文件中必然包含这两行,务必保留。
3.5 版本校验段:防止低版本 MySQL 执行失败
文件末尾有兼容性检测:
-- Version check: abort if MySQL < 5.7 SELECT IF(VERSION() < '5.7.0', CONCAT('ERROR: This dump requires MySQL 5.7 or higher, but you are running ', VERSION()), 'OK') AS version_check;若你用 5.6,此查询会返回ERROR...,但不会中断执行(因是SELECT)。你需要手动删掉这行,或升级 MySQL。
4. 本地导入实战:从下载文件到可查询的 4 步命令,含参数详解与失败诊断
假设你已下载shici_database_v2.3.sql到/home/user/data/,以下是在 Linux/macOS 终端完成导入的最小可行路径。Windows 用户请用 Git Bash 或 WSL,避免 PowerShell 的编码陷阱。
4.1 第一步:创建数据库并指定字符集(关键!)
mysql -u root -p -e "CREATE DATABASE shici_db CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;"-e参数执行单条 SQL,免进交互模式;CHARACTER SET = utf8mb4必须显式声明,否则 MySQL 5.7+ 默认用latin1,后续导入中文全变??;COLLATE = utf8mb4_unicode_ci支持中文排序(如ORDER BY name按笔画序),比utf8mb4_general_ci更准。
4.2 第二步:执行 SQL 文件(核心命令)
mysql -u root -p shici_db < /home/user/data/shici_database_v2.3.sql<是 shell 重定向,将文件内容作为输入传给mysql客户端;- 不要加
-e,否则会把整个文件当一条 SQL 执行,报错ERROR 1064; - 若文件超 100MB,建议加
--default-character-set=utf8mb4显式指定编码:
mysql --default-character-set=utf8mb4 -u root -p shici_db < /home/user/data/shici_database_v2.3.sql4.3 第三步:验证导入完整性(3 条必查 SQL)
导入完成后,立即运行以下查询,确认核心数据未截断:
-- 1. 检查诗人总数(v2.3 应为 3,827 人) SELECT COUNT(*) FROM shici_db.poets; -- 2. 检查诗作总数(v2.3 应为 52,814 首) SELECT COUNT(*) FROM shici_db.poems; -- 3. 检查是否有 NULL 生卒年(合理,因部分诗人年代不可考) SELECT COUNT(*) FROM shici_db.poets WHERE birth_year IS NULL OR death_year IS NULL; -- 预期返回 1,204(约31%诗人年代不详,属正常)提示:若
COUNT(*)远低于预期(如诗人只有 100 条),大概率是字符集错误或 SQL 模式冲突。此时不要重跑,先查错误日志:tail -n 50 /var/log/mysql/error.log,常见报错Incorrect string value直接指向字符集问题。
4.4 第四步:测试典型查询(验证字段可用性)
用一个真实业务场景验证:查李白所有五言绝句,按字数升序排列。
SELECT p.title, p.char_count, p.content FROM shici_db.poems p JOIN shici_db.poets t ON p.poet_id = t.id WHERE t.name = '李白' AND p.line_count = 5 AND p.char_count BETWEEN 18 AND 22 -- 五绝正文字数通常20字(4句×5字) ORDER BY p.char_count ASC LIMIT 5;- 返回应有《静夜思》《夜宿山寺》等,
content字段显示为带\n的多行文本; - 若
content显示为乱码(如æŽç½),立刻回退到第 4.1 步,重建数据库并确认CHARACTER SET。
5. 避坑指南:5 个血泪经验总结,专治导入失败、查询不准、性能卡顿
这些坑,都是某开发者在凌晨三点调试时用SHOW PROCESSLIST和EXPLAIN一帧帧扒出来的。跳过它们,能省你至少 8 小时。
5.1 现象:导入后poets.name出现乱码(如æŽç½),但poems.content正常
原因:数据库创建时未指定CHARACTER SET utf8mb4,仅客户端设了SET NAMES utf8mb4。MySQL 会把name字段按表默认字符集(如latin1)存储,而content因字段级CHARACTER SET utf8mb4仍正确。
解决:重建数据库,并确认CREATE DATABASE语句含CHARACTER SET = utf8mb4;已有库可执行ALTER DATABASE shici_db CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;,但已存乱码数据需重新导入。
5.2 现象:FULLTEXT搜索MATCH(bio_summary) AGAINST('杜甫')返回空
原因:MySQL 8.0+ 默认innodb_ft_min_token_size=3,而“杜甫”仅2字符,被全文索引引擎忽略。
解决:修改 MySQL 配置文件my.cnf,在[mysqld]段添加:
innodb_ft_min_token_size=2然后重启 MySQL,并重建全文索引:
ALTER TABLE shici_db.poets DROP INDEX ft_bio; ALTER TABLE shici_db.poets ADD FULLTEXT ft_bio (bio_summary);5.3 现象:SELECT * FROM poems WHERE content LIKE '%春风%'极慢(>10秒)
原因:LIKE左模糊(%春风)无法用普通 B+Tree 索引,全表扫描 5 万行。
解决:改用全文索引:
-- 确保 poems 表有 FULLTEXT 索引(v2.3 已含) SELECT title, content FROM shici_db.poems WHERE MATCH(content) AGAINST('春风' IN NATURAL LANGUAGE MODE);速度提升至 0.02 秒。注意:AGAINST中关键词不能含*(如'春风*'是布尔模式语法,需IN BOOLEAN MODE)。
5.4 现象:导入时卡在poem_tags表,报错ERROR 1452: Cannot add or update a child row
原因:poem_tags.poem_id或tag_id引用的poems.id/tags.id在对应表中不存在。常见于手动删减数据后未同步清理关联表。
解决:先查缺失 ID:
SELECT DISTINCT pt.poem_id FROM shici_db.poem_tags pt LEFT JOIN shici_db.poems p ON pt.poem_id = p.id WHERE p.id IS NULL;若返回非空,说明poem_tags有“孤儿记录”,需删除或补全poems数据。
5.5 现象:MySQL 5.7 导入失败,报错Unknown collation: 'utf8mb4_0900_as_cs'
原因:utf8mb4_0900_as_cs是 MySQL 8.0.1 新增的排序规则,5.7 不识别。
解决:用sed命令全局替换(Linux/macOS):
sed -i 's/utf8mb4_0900_as_cs/utf8mb4_unicode_ci/g' /home/user/data/shici_database_v2.3.sqlWindows 用户可用 Notepad++ 的“全部替换”,将utf8mb4_0900_as_cs替换为utf8mb4_unicode_ci。
6. 进阶技巧:3 个让诗词数据库真正活起来的实战用法,附可抄代码
数据库建好只是起点。让它服务于真实需求,才是价值所在。以下三个技巧,我已在某高校古典文学数字人文课、某诗词 APP 后端、某 NLP 训练 pipeline 中反复验证。
6.1 技巧一:用视图封装复杂查询,让业务代码只写SELECT * FROM tang_poems
业务方(如前端工程师)不该记住poets.dynasty='唐' AND poems.line_count=8这种耦合条件。建视图抽象:
CREATE VIEW tang_poems AS SELECT p.id AS poem_id, p.title, p.content, t.name AS poet_name, t.courtesy_name, t.hao, p.char_count, p.rhyme_scheme FROM shici_db.poems p JOIN shici_db.poets t ON p.poet_id = t.id WHERE t.dynasty = '唐';- 使用:
SELECT * FROM tang_poems WHERE char_count = 40 LIMIT 10;(唐律正文字数40字) - 优势:业务代码无需 JOIN,字段名语义清晰(
poet_name而非t.name),且视图可加WITH CHECK OPTION防止误更新。
6.2 技巧二:生成诗人-诗作关系图谱(CSV 导出供 Gephi 分析)
研究诗人交游网络?用 SQL 导出边列表(诗人A → 诗人B,若两人同题唱和):
-- 导出同题唱和关系(简化版:同一诗题下多位诗人) SELECT p1.name AS source_poet, p2.name AS target_poet, COUNT(*) AS co_occurrence FROM shici_db.poems pm1 JOIN shici_db.poets p1 ON pm1.poet_id = p1.id JOIN shici_db.poems pm2 ON pm1.title = pm2.title AND pm1.id != pm2.id JOIN shici_db.poets p2 ON pm2.poet_id = p2.id WHERE p1.dynasty = p2.dynasty -- 限定同朝代 GROUP BY p1.name, p2.name HAVING co_occurrence >= 2 -- 至少2次同题 ORDER BY co_occurrence DESC INTO OUTFILE '/tmp/tang_poet_cooccurrence.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n';- 输出 CSV 可直接拖入 Gephi,用 “Force Atlas 2” 布局,诗人节点大小按
co_occurrence加权,瞬间看清杜甫、高适、岑参的边塞诗圈层。
6.3 技巧三:为 LLM 微调准备指令微调数据集(JSONL 格式)
训练古诗续写模型?用 SQL 生成instruction/input/output三元组:
SELECT CONCAT('续写这首', CASE WHEN p.line_count = 4 THEN '绝句' ELSE '律诗' END, '的后两句:') AS instruction, SUBSTRING_INDEX(p.content, '\n', 2) AS input, -- 前两句 SUBSTRING_INDEX(p.content, '\n', -2) AS output -- 后两句 FROM shici_db.poems p JOIN shici_db.poets t ON p.poet_id = t.id WHERE t.dynasty = '唐' AND p.line_count IN (4, 8) AND LENGTH(p.content) - LENGTH(REPLACE(p.content, '\n', '')) >= 3 -- 至少4句 LIMIT 1000 INTO OUTFILE '/tmp/tang_poem_finetune.jsonl' FIELDS TERMINATED BY '' LINES TERMINATED BY '\n';- 输出为每行一个 JSON 对象:
{"instruction":"续写这首绝句的后两句:","input":"床前明月光\n疑是地上霜","output":"举头望明月\n低头思故乡"}- 此 JSONL 可直喂 Hugging Face
Trainer,无需额外 Python 清洗。
最后说句实在话:这个数据库不是终点,而是你所有古诗文项目的“地基”。我见过太多团队,花两周爬数据、三天调编码、一天修乱码,最后发现字段设计根本撑不起“按押韵格式检索”这种基础需求。而一份经过生产环境锤炼的.sql文件,能让你把精力真正放在“怎么用诗”上,而不是“怎么救数据”上。希望帮到你。
本文还有配套的精品资源,点击获取