数据库与数据表
导学
在写 SQL 之前,必须先建立两个核心概念:数据库(Database)和数据表(Table)。它们是 MySQL 组织数据的两个最基本层级。本节会用"图书馆"做类比,并通过完整的 SQL 示例让你建立直观认知,观察每一步操作前后的数据状态变化。
定义
数据库(Database):一个逻辑上的数据容器,用于将一组相关的数据表、视图、存储过程等对象组织在一起。可以把数据库想象成一座图书馆。
数据表(Table):数据库中存储数据的二维结构,由行(Row)和列(Column)组成。可以把数据表想象成图书馆里的一张具体的书架。
行与列
数据表的核心是行和列:
- 列(Column):定义了数据的属性,如书名、作者、价格。每列有固定的数据类型。
- 行(Row):一条具体的记录,如《数据库系统概念》这本书的所有信息。
关系型数据库的核心特征
关系型数据库之所以叫"关系型",是因为表与表之间可以通过公共字段建立关系(Relationship)。
上图中:
PK= Primary Key(主键),唯一标识一行记录FK= Foreign Key(外键),建立表与表之间的关系
完整示例:从创建数据库到建立表关系
当前数据状态:查看服务器上已有的数据库
SHOW DATABASES;
典型的执行结果:
| Database |
|---|
| information_schema |
| mysql |
| performance_schema |
| sys |
结果解读:新安装的 MySQL 5.7 默认有 4 个系统数据库,不要修改它们。
操作语句:创建图书馆数据库
CREATE DATABASE IF NOT EXISTS library
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_unicode_ci;
操作后的数据状态
SHOW DATABASES;
| Database |
|---|
| information_schema |
| library |
| mysql |
| performance_schema |
| sys |
结果解读:library 数据库已创建,现在它是空的容器。
操作语句:在数据库中创建多张表
USE library;
-- 创建员工表
CREATE TABLE employees (
emp_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '员工ID',
emp_name VARCHAR(20) NOT NULL COMMENT '姓名',
dept VARCHAR(20) DEFAULT '技术部' COMMENT '部门',
score DECIMAL(5,2) COMMENT '绩效分'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='员工表';
-- 创建绩效记录表(演示表间关系)
CREATE TABLE scores (
score_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '记录ID',
emp_id INT NOT NULL COMMENT '员工ID',
score DECIMAL(5,2) COMMENT '绩效分',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='绩效记录表';
操作后的数据状态
SHOW TABLES;
| Tables_in_library |
|---|
| employees |
| scores |
结果解读:一个数据库(图书馆)中现在有了两张表(两个书架),它们通过外键建立了关系。
查看表结构的对应关系:
DESC employees;
| Field | Type | Null | Key | Default | Extra |
|---|---|---|---|---|---|
| emp_id | int(11) | NO | PRI | NULL | auto_increment |
| emp_name | varchar(20) | NO | NULL | ||
| dept | varchar(20) | YES | 技术部 | ||
| score | decimal(5,2) | YES | NULL |
DESC scores;
| Field | Type | Null | Key | Default | Extra |
|---|---|---|---|---|---|
| score_id | int(11) | NO | PRI | NULL | auto_increment |
| emp_id | int(11) | NO | MUL | NULL | |
| score | decimal(5,2) | YES | NULL | ||
| created_at | timestamp | YES | CURRENT_TIMESTAMP |
结果解读:scores 表的 emp_id 列的 Key 字段显示为 MUL,表示它是多列索引的一部分(这里是外键索引)。
完整示例二:USE 切换数据库
当前数据状态
SELECT DATABASE();
| DATABASE() |
|---|
| library |
结果解读:当前会话默认在 library 数据库中。
操作语句:切换到系统数据库
USE mysql;
SHOW TABLES;
操作后的数据状态:
SELECT DATABASE();
| DATABASE() |
|---|
| mysql |
结果解读:USE 语句选择当前会话要操作的数据库。执行后,后续的查询默认在该数据库中进行。mysql 库中的表是系统表,例如 user 表存储了所有用户账号信息。
查看当前库中的表(节选):
SHOW TABLES LIKE 'user%';
| Tables_in_mysql (user%) |
|---|
| user |
切换回自己的数据库:
USE library;
完整示例三:验证表之间的关系
当前数据状态
SELECT * FROM employees;
SELECT * FROM scores;
Empty set (0.00 sec)
结果解读:两张表都是空的。现在插入数据,验证关系型数据库的核心价值。
操作语句:插入数据
-- 插入员工
INSERT INTO employees (emp_name, dept, score) VALUES
('大翔', '技术部', 100),
('白歌', '技术部', NULL);
操作后的数据状态
SELECT * FROM employees;
| emp_id | emp_name | dept | score |
|---|---|---|---|
| 1 | 大翔 | 技术部 | 100 |
| 2 | 白歌 | 技术部 | NULL |
结果解读:employees 表存储了员工的基本信息,通过 emp_id 唯一标识每行记录。
操作语句:建立绩效记录关系
INSERT INTO scores (emp_id, score) VALUES
(1, 90);
操作后的数据状态
SELECT * FROM scores;
| score_id | emp_id | score | created_at |
|---|---|---|---|
| 1 | 1 | 90.00 | 2024-01-15 10:35:00 |
结果解读:scores 表通过 emp_id 记录了"哪位员工的绩效分"。这就是关系型数据库的核心:不把所有信息塞在一张表里,而是通过关联字段连接多张表。
查询大翔的绩效记录(演示 JOIN):
SELECT
e.emp_name AS 员工,
s.score AS 绩效分,
s.created_at AS 记录时间
FROM scores s
JOIN employees e ON s.emp_id = e.emp_id
WHERE e.emp_name = '大翔';
| 员工 | 绩效分 | 记录时间 |
|---|---|---|
| 大翔 | 90.00 | 2024-01-15 10:35:00 |
结果解读:通过 JOIN 操作,我们从两张独立的表中组合出了有意义的业务信息。这是关系型数据库最强大的能力。
完整示例四:验证外键的引用完整性
当前数据状态
SELECT emp_id, emp_name FROM employees;
| emp_id | emp_name |
|---|---|
| 1 | 大翔 |
| 2 | 白歌 |
操作语句:尝试插入不存在的员工ID
INSERT INTO scores (emp_id, score) VALUES (999, 85);
操作后的数据状态
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
结果解读:外键约束阻止了非法数据的插入。emp_id = 999 在 employees 表中不存在,因此无法创建绩效记录。这就是关系型数据库保证数据一致性的机制。
常见误区
| 误区 | 正解 |
|---|---|
| "数据库就是数据表" | 数据库是容器,数据表是容器内的对象。一个数据库可包含多张表。 |
| "MySQL 只能有一个数据库" | 一个 MySQL 实例可以创建成百上千个数据库,受磁盘空间和配置限制。 |
| "表名可以随便起" | 表名在同一数据库内必须唯一,且应避免使用 SQL 保留字(如 order、select)。 |
验证保留字问题:
-- 尝试用保留字做表名(会报错或需要反引号)
CREATE TABLE order (id INT);
ERROR 1064 (42000): You have an error in your SQL syntax
正确使用反引号:
CREATE TABLE `order` (id INT PRIMARY KEY);
SHOW TABLES;
| Tables_in_library |
|---|
| employees |
| order |
| scores |
-- 清理测试表
DROP TABLE `order`;
结果解读:虽然可以用反引号包裹保留字作为表名,但这会导致后续所有查询都需要加反引号,极不推荐。
面试考点
Q:information_schema 是什么?
它是 MySQL 的元数据数据库(虚拟数据库,无实际物理文件),存储了所有数据库、表、列、索引、权限等元信息。例如查询
information_schema.TABLES可获知所有表的大小和引擎类型。
验证:
SELECT
table_name,
engine,
table_rows
FROM information_schema.tables
WHERE table_schema = 'library'
ORDER BY table_name;
| table_name | engine | table_rows |
|---|---|---|
| employees | InnoDB | 2 |
| scores | InnoDB | 1 |
结果解读:information_schema.tables 提供了所有表的标准化元数据查询能力。
Q:一个 MySQL 实例最多能有多少个数据库?
没有硬性上限,受操作系统文件描述符和目录限制。实际生产中,单实例管理的数据库数量建议控制在合理范围内(如几百个),过多会影响运维效率。
小结
- 数据库 = 图书馆,数据表 = 书架
- 表由行(记录)和列(属性)组成
- 关系型数据库的核心价值在于表与表之间可以通过主键/外键建立关系
- MySQL 自带 4 个系统数据库,不要轻易动它们
- 外键约束保证了数据的引用完整性
清理测试数据库(可选):
-- DROP DATABASE IF EXISTS library;
下一章引子:概念清楚了,接下来我们动手连接 MySQL 服务器,执行第一条命令。