-- 创建势力表(预定义势力)
CREATE TABLE kingdoms (
kingdom_id TINYINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(10) NOT NULL UNIQUE
) COMMENT '三国势力表';
-- 插入基本势力
INSERT INTO kingdoms (name) VALUES ('魏'), ('蜀'), ('吴'), ('其他');
-- 创建人物主表
CREATE TABLE heroes (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
name VARCHAR(20) NOT NULL COMMENT '人物姓名',
kingdom_id TINYINT UNSIGNED NOT NULL COMMENT '所属势力ID',
role ENUM('君主', '武将', '谋士', '文官') NOT NULL COMMENT '角色类型',
strength TINYINT UNSIGNED DEFAULT 0 COMMENT '武力值(0-100)',
intelligence TINYINT UNSIGNED DEFAULT 0 COMMENT '智力值(0-100)',
birth_year SMALLINT COMMENT '出生年份',
death_year SMALLINT COMMENT '死亡年份',
gender ENUM('男', '女') NOT NULL DEFAULT '男' COMMENT '性别',
CONSTRAINT chk_stats CHECK (strength BETWEEN 0 AND 100 AND intelligence BETWEEN 0 AND 100),
CONSTRAINT fk_kingdom FOREIGN KEY (kingdom_id) REFERENCES kingdoms(kingdom_id)
) ENGINE=InnoDB COMMENT '三国人物信息表';
-- 创建索引(优化查询性能)
CREATE INDEX idx_heroes_role ON heroes(role);
CREATE INDEX idx_heroes_name ON heroes(name);
-- 插入势力数据(已在建表时完成)
-- 插入人物数据
INSERT INTO heroes (name, kingdom_id, role, strength, intelligence, birth_year, death_year, gender) VALUES
('刘备', (SELECT kingdom_id FROM kingdoms WHERE name='蜀'), '君主', 75, 85, 161, 223, '男'),
('关羽', (SELECT kingdom_id FROM kingdoms WHERE name='蜀'), '武将', 95, 75, 160, 220, '男'),
('张飞', (SELECT kingdom_id FROM kingdoms WHERE name='蜀'), '武将', 92, 60, 168, 221, '男'),
('诸葛亮', (SELECT kingdom_id FROM kingdoms WHERE name='蜀'), '谋士', 65, 99, 181, 234, '男'),
('曹操', (SELECT kingdom_id FROM kingdoms WHERE name='魏'), '君主', 80, 90, 155, 220, '男'),
('司马懿', (SELECT kingdom_id FROM kingdoms WHERE name='魏'), '谋士', 70, 95, 179, 251, '男'),
('孙权', (SELECT kingdom_id FROM kingdoms WHERE name='吴'), '君主', 70, 85, 182, 252, '男'),
('周瑜', (SELECT kingdom_id FROM kingdoms WHERE name='吴'), '谋士', 75, 95, 175, 210, '男'),
('吕布', (SELECT kingdom_id FROM kingdoms WHERE name='其他'), '武将', 99, 40, 161, 199, '男'),
('貂蝉', (SELECT kingdom_id FROM kingdoms WHERE name='其他'), '谋士', 30, 85, NULL, NULL, '女'),
('孙尚香', (SELECT kingdom_id FROM kingdoms WHERE name='吴'), '武将', 82, 75, 184, NULL, '女'),
('黄月英', (SELECT kingdom_id FROM kingdoms WHERE name='蜀'), '谋士', 40, 92, 185, 219, '女');
基础联合查询:
-- 查询所有人物及其所属势力
SELECT h.name, k.name AS kingdom, h.role, h.strength, h.intelligence
FROM heroes h
JOIN kingdoms k ON h.kingdom_id = k.kingdom_id;
高级统计查询:
-- 各势力文官平均智力值排行
SELECT
k.name AS 势力,
COUNT(*) AS 文官人数,
AVG(h.intelligence) AS 平均智力值
FROM heroes h
JOIN kingdoms k ON h.kingdom_id = k.kingdom_id
WHERE h.role IN ('谋士', '文官')
GROUP BY k.name
ORDER BY 平均智力值 DESC;
条件计算查询:
-- 查询健在人物的年龄(假设当前是公元230年)
SELECT
name,
birth_year,
230 - birth_year AS 年龄,
CASE
WHEN gender = '女' THEN CONCAT('女士')
ELSE CONCAT('先生')
END AS 称谓
FROM heroes
WHERE death_year IS NULL
ORDER BY 年龄 DESC;
-- 创建战役类型表
CREATE TABLE battle_types (
type_id TINYINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL COMMENT '战役类型',
description VARCHAR(100) COMMENT '类型说明'
);
-- 插入战役类型
INSERT INTO battle_types (name, description) VALUES
('水战', '水上作战'),
('陆战', '陆地作战'),
('攻城战', '城市攻防战'),
('伏击战', '埋伏奇袭作战'),
('遭遇战', '意外遭遇作战');
-- 创建战役主表
CREATE TABLE battles (
battle_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '战役ID',
name VARCHAR(30) NOT NULL UNIQUE COMMENT '战役名称',
year SMALLINT NOT NULL COMMENT '发生年份',
location VARCHAR(50) NOT NULL COMMENT '发生地点(古地名)',
location_now VARCHAR(50) COMMENT '现代地名',
attacker_kingdom_id TINYINT UNSIGNED NOT NULL COMMENT '进攻方势力ID',
defender_kingdom_id TINYINT UNSIGNED NOT NULL COMMENT '防守方势力ID',
type_id TINYINT UNSIGNED NOT NULL COMMENT '战役类型ID',
result ENUM('进攻方胜', '防守方胜', '平局', '无结果') NOT NULL COMMENT '战役结果',
duration_days SMALLINT UNSIGNED COMMENT '持续天数',
CONSTRAINT fk_attacker FOREIGN KEY (attacker_kingdom_id) REFERENCES kingdoms(kingdom_id),
CONSTRAINT fk_defender FOREIGN KEY (defender_kingdom_id) REFERENCES kingdoms(kingdom_id),
CONSTRAINT fk_battle_type FOREIGN KEY (type_id) REFERENCES battle_types(type_id)
) COMMENT '三国战役记录表';
-- 创建战役人物关联表
CREATE TABLE battle_commanders (
battle_id INT NOT NULL COMMENT '战役ID',
commander_id INT NOT NULL COMMENT '主将ID',
role ENUM('主将', '副将', '军师') NOT NULL COMMENT '角色',
is_attacker BOOLEAN NOT NULL COMMENT '是否进攻方',
PRIMARY KEY (battle_id, commander_id),
FOREIGN KEY (battle_id) REFERENCES battles(battle_id),
FOREIGN KEY (commander_id) REFERENCES heroes(id)
) COMMENT '战役指挥官表';
-- 插入战役数据
INSERT INTO battles (name, year, location, location_now, attacker_kingdom_id, defender_kingdom_id, type_id, result, duration_days) VALUES
('赤壁之战', 208, '赤壁', '湖北赤壁市',
(SELECT kingdom_id FROM kingdoms WHERE name='魏'),
(SELECT kingdom_id FROM kingdoms WHERE name='吴'),
(SELECT type_id FROM battle_types WHERE name='水战'),
'防守方胜', 60),
('官渡之战', 200, '官渡', '河南中牟县',
(SELECT kingdom_id FROM kingdoms WHERE name='魏'),
(SELECT kingdom_id FROM kingdoms WHERE name='其他'), -- 袁绍势力
(SELECT type_id FROM battle_types WHERE name='陆战'),
'进攻方胜', 120),
('夷陵之战', 222, '夷陵', '湖北宜昌市',
(SELECT kingdom_id FROM kingdoms WHERE name='蜀'),
(SELECT kingdom_id FROM kingdoms WHERE name='吴'),
(SELECT type_id FROM battle_types WHERE name='遭遇战'),
'防守方胜', 90),
('合肥之战', 215, '合肥', '安徽合肥市',
(SELECT kingdom_id FROM kingdoms WHERE name='吴'),
(SELECT kingdom_id FROM kingdoms WHERE name='魏'),
(SELECT type_id FROM battle_types WHERE name='攻城战'),
'防守方胜', 45),
('汉中之战', 219, '汉中', '陕西汉中市',
(SELECT kingdom_id FROM kingdoms WHERE name='蜀'),
(SELECT kingdom_id FROM kingdoms WHERE name='魏'),
(SELECT type_id FROM battle_types WHERE name='攻城战'),
'进攻方胜', 180);
-- 插入战役主将数据
INSERT INTO battle_commanders (battle_id, commander_id, role, is_attacker) VALUES
-- 赤壁之战
((SELECT battle_id FROM battles WHERE name='赤壁之战'),
(SELECT id FROM heroes WHERE name='曹操'), '主将', 1),
((SELECT battle_id FROM battles WHERE name='赤壁之战'),
(SELECT id FROM heroes WHERE name='周瑜'), '主将', 0),
-- 官渡之战
((SELECT battle_id FROM battles WHERE name='官渡之战'),
(SELECT id FROM heroes WHERE name='曹操'), '主将', 1),
-- 夷陵之战
((SELECT battle_id FROM battles WHERE name='夷陵之战'),
(SELECT id FROM heroes WHERE name='刘备'), '主将', 1),
((SELECT battle_id FROM battles WHERE name='夷陵之战'),
(SELECT id FROM heroes WHERE name='陆逊'), '主将', 0),
-- 合肥之战
((SELECT battle_id FROM battles WHERE name='合肥之战'),
(SELECT id FROM heroes WHERE name='张辽'), '主将', 0),
-- 汉中之战
((SELECT battle_id FROM battles WHERE name='汉中之战'),
(SELECT id FROM heroes WHERE name='刘备'), '主将', 1),
((SELECT battle_id FROM battles WHERE name='汉中之战'),
(SELECT id FROM heroes WHERE name='曹操'), '主将', 0);
基础战役查询:
-- 查询赤壁之战详细信息
SELECT
b.name AS 战役名称,
b.year AS 年份,
b.location_now AS 现代位置,
attack.name AS 进攻方,
defend.name AS 防守方,
bt.name AS 战役类型,
b.result AS 结果
FROM battles b
JOIN kingdoms attack ON b.attacker_kingdom_id = attack.kingdom_id
JOIN kingdoms defend ON b.defender_kingdom_id = defend.kingdom_id
JOIN battle_types bt ON b.type_id = bt.type_id
WHERE b.name = '赤壁之战';
高级人物关联查询:
-- 查询曹操参与的所有战役
SELECT
b.name AS 战役,
b.year AS 年份,
CASE
WHEN bc.is_attacker = 1 THEN '进攻方'
ELSE '防守方'
END AS 参战方,
b.result AS 结果
FROM battle_commanders bc
JOIN battles b ON bc.battle_id = b.battle_id
JOIN heroes h ON bc.commander_id = h.id
WHERE h.name = '曹操';
统计型查询:
-- 各类型战役胜负统计
SELECT
bt.name AS 战役类型,
COUNT(*) AS 总场次,
SUM(CASE WHEN b.result = '进攻方胜' THEN 1 ELSE 0 END) AS 进攻方胜,
SUM(CASE WHEN b.result = '防守方胜' THEN 1 ELSE 0 END) AS 防守方胜,
SUM(CASE WHEN b.result IN ('平局', '无结果') THEN 1 ELSE 0 END) AS 平局无结果,
ROUND(AVG(b.duration_days), 1) AS 平均持续天数
FROM battles b
JOIN battle_types bt ON b.type_id = bt.type_id
GROUP BY bt.name;
-- 创建武将能力视图
CREATE VIEW commander_abilities AS
SELECT
h.name AS 姓名,
k.name AS 势力,
h.strength AS 武力,
h.intelligence AS 智力,
ROUND((h.strength + h.intelligence) / 2, 1) AS 综合能力,
DENSE_RANK() OVER (ORDER BY (h.strength + h.intelligence) DESC) AS 能力排名
FROM heroes h
JOIN kingdoms k ON h.kingdom_id = k.kingdom_id
WHERE h.role IN ('君主', '武将', '谋士');
-- 使用视图查询
SELECT * FROM commander_abilities ORDER BY 能力排名 LIMIT 10;
-- 各战役位置地理分布
SELECT
b.location_now AS 现代位置,
COUNT(*) AS 战役次数,
GROUP_CONCAT(b.name ORDER BY b.year SEPARATOR '、') AS 战役列表
FROM battles b
GROUP BY b.location_now
HAVING COUNT(*) >= 1
ORDER BY COUNT(*) DESC;
-- 主将能力对胜负的影响
SELECT
b.name AS 战役,
CASE
WHEN b.result = '进攻方胜' THEN ac.name
WHEN b.result = '防守方胜' THEN dc.name
ELSE '平局'
END AS 胜方主将,
bc_att.武力 AS 胜方武力,
bc_att.智力 AS 胜方智力,
b.result AS 结果
FROM battles b
JOIN (
SELECT battle_id, commander_id
FROM battle_commanders
WHERE role = '主将' AND is_attacker = 1
) att ON b.battle_id = att.battle_id
JOIN (
SELECT battle_id, commander_id
FROM battle_commanders
WHERE role = '主将' AND is_attacker = 0
) def ON b.battle_id = def.battle_id
JOIN commander_abilities ac ON att.commander_id = ac.姓名
JOIN commander_abilities dc ON def.commander_id = dc.姓名;
规范化设计:
历史准确性:
实用功能:
教学价值:
这个优化版本更适合初学者学习,通过三国主题的实际案例,帮助掌握数据库设计的核心概念和SQL查询的精髓。