3. 数据库设计基础:关系型数据库概念、ER图设计、药盒用户表(user)字段定义
好,咱们进入第三个核心环节——数据库设计。说实话,很多初学者觉得数据库设计就是建几张表,随便写几个字段就完事了。我以前也这么想,直到有一次在项目里,因为表结构设计不合理,导致后期查询慢得像蜗牛爬,还被运维大哥吐槽了一整天……从那以后,我每次动手前都会老老实实画ER图、想清楚字段类型。
这一章,咱们就围绕药盒系统的用户数据存储,把关系型数据库的基础概念、ER图怎么画、以及user表到底该怎么定义,一次性讲透。
3.1 关系型数据库到底是什么?
说白了,关系型数据库就是一张张表格的集合。你想想看,Excel表格是不是也有行和列?关系型数据库里的“表”就类似Excel的sheet,每一行是一条记录,每一列是一个字段。
我个人的理解是:关系型数据库的核心在于“关系”二字。什么意思呢?就是表与表之间可以通过某些字段关联起来。比如用户表里有个字段叫“药盒ID”,药盒表里也有这个ID,那这两张表就能通过这个ID建立联系。
常见的数据库有MySQL、PostgreSQL、SQLite等。咱们这个药盒系统,我建议用SQLite,因为它轻量、不需要单独安装服务,非常适合嵌入式或小规模应用。嗯,这里要注意:如果你以后做大型项目,还是得用MySQL或PostgreSQL。
关系型数据库的三大特点:
- 结构化存储:数据以表格形式组织,每行每列都有明确含义
- 支持SQL查询:用结构化查询语言操作数据,非常灵活
- 保证数据一致性:通过事务、约束等机制,防止数据出错
3.2 ER图设计——先画图,再建表
我见过太多人上来就写SQL建表,结果建到一半发现字段不够用,或者表之间关系搞混了。我的习惯是:先画ER图,再写代码。ER图就是实体-关系图,它帮我们把现实世界中的对象和它们之间的关系可视化。
咱们药盒系统,核心实体有哪些?我列一下:
- 用户(User):用药的人
- 药盒(Box):物理药盒设备
- 用药计划(MedicationPlan):什么时候吃什么药
- 服药记录(MedicationLog):每次服药的实际记录
它们之间的关系是这样的:
- 一个用户可以有多个药盒(一对多)
- 一个药盒可以有多个用药计划(一对多)
- 一个用药计划对应多条服药记录(一对多)
画成ER图,大概长这样(文字描述版):
[用户] 1 —— N [药盒] 1 —— N [用药计划] 1 —— N [服药记录]
你想想看,如果一开始没画这个图,直接建表,很容易漏掉“药盒”这个实体。我以前就犯过这个错,把药盒信息直接塞到用户表里,结果一个用户有多个药盒时,数据冗余得一塌糊涂。
小技巧:画ER图时,先找出所有名词(用户、药盒、计划、记录),再找出动词(拥有、包含、记录),关系就出来了。用纸笔或者draw.io都行,别纠结工具。
3.3 药盒用户表(user)字段定义
好,重点来了。咱们先聚焦用户表,这是整个系统的基石。我直接给出字段定义,然后逐个解释为什么这么设计。
| 字段名 | 类型 | 长度 | 约束 | 说明 |
|---|---|---|---|---|
| id | INTEGER | - | PRIMARY KEY, AUTOINCREMENT | 用户唯一标识,自增主键 |
| name | VARCHAR | 50 | NOT NULL | 用户姓名 |
| age | INTEGER | - | CHECK(age > 0 AND age < 150) | 年龄,加约束防止非法数据 |
| phone | VARCHAR | 20 | UNIQUE, NOT NULL | 手机号,唯一且必填 |
| medication_plan | TEXT | - | - | 用药计划(JSON格式存储) |
我来逐个说说设计思路:
- id:每个表都应该有一个主键,这是数据库设计的铁律。我习惯用自增整数,简单高效。UUID虽然更安全,但查询性能稍差,小项目没必要。
- name:VARCHAR(50)够用了,中国人名字最长也就四五个字,50个字符绰绰有余。记得加NOT NULL,因为不知道用户叫啥,这系统就没意义了。
- age:用整数,加CHECK约束。我曾经接手过一个项目,年龄字段居然存了“-5”这种值,就是因为没加约束。嗯,这里要注意:年龄最好用整数,别用字符串,否则排序和计算都会出问题。
- phone:手机号用VARCHAR,别用整数。为什么呢?因为手机号可能以0开头,如果用整数存储,前面的0就丢了。加UNIQUE约束,保证一个手机号只能注册一个用户。
- medication_plan:这个字段比较特殊。用药计划可能包含多种药、多个时间段,结构比较复杂。我建议用TEXT类型,存储JSON字符串。这样既灵活,又不需要额外建关联表。当然,如果你追求严格的数据库范式,可以单独建一张plan表。但咱们这个系统规模不大,JSON方案更实用。
避坑指南:我曾经在一个项目里把phone字段设成了INTEGER,结果用户输入“010-12345678”时,数据库直接报错。后来花了半天时间改表结构……所以记住:凡是可能包含非数字字符的字段,一律用VARCHAR。
3.4 建表SQL示例
光说不练假把式,咱们直接上SQL代码。这是创建user表的完整语句:
CREATE TABLE user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(50) NOT NULL,
age INTEGER CHECK(age > 0 AND age < 150),
phone VARCHAR(20) UNIQUE NOT NULL,
medication_plan TEXT
);
这段代码在SQLite里可以直接运行。如果你用MySQL,把AUTOINCREMENT改成AUTO_INCREMENT就行。其他数据库也大同小异。
我个人建议:建表时就把约束写全,别想着“以后再加”。因为数据一旦多起来,加约束的成本会非常高。你想想看,如果表里已经有一万条数据,突然要加一个UNIQUE约束,结果发现有重复值……那场面,啧啧。
3.5 本章小结
这一章咱们干了三件事:
- 理解了关系型数据库的本质——就是一张张有关联的表格
- 画了药盒系统的ER图,理清了用户、药盒、计划、记录之间的关系
- 详细定义了user表的5个字段,每个字段的类型、约束、设计理由都讲清楚了
下一章,咱们会继续设计药盒表(box)和用药计划表(medication_plan),到时候你会看到表与表之间是怎么通过外键关联起来的。嗯,敬请期待。