3. 数据库设计(上):ER图设计、合同主表字段设计
数据库设计是工程合同义务跟踪系统的数据基石。本章聚焦于概念模型(ER图)与逻辑模型(合同主表字段),为后续的义务分解、动态监控接口提供稳定的数据结构。
3.1 核心实体关系(ER图)
工程合同义务跟踪系统涉及四个核心实体:合同、合同义务、参与方、履行记录。它们之间的关系如下:
- 合同 与 合同义务:一对多(1:N)。一份合同包含多项义务(付款、验收、提交资料等)。
- 合同 与 参与方:多对多(M:N)。一份合同有甲方、乙方、监理方;一个参与方可参与多份合同。
- 合同义务 与 履行记录:一对多(1:N)。一项义务可产生多次履行记录(如分期付款)。
设计原则: 合同主表只存储合同级静态属性,义务、参与方、履行记录均拆分为子表,确保数据无冗余、更新无异常。
3.2 合同主表字段设计
合同主表(contract)是系统的核心表,存储合同级静态信息。字段设计遵循最小化、标准化原则,避免将义务、参与方等动态数据混入主表。
| 字段名 | 数据类型 | 长度 | 约束 | 说明 |
|---|---|---|---|---|
id |
BIGINT | — | PK, AUTO_INCREMENT | 自增主键 |
contract_code |
VARCHAR | 50 | UNIQUE, NOT NULL | 合同编号(业务唯一标识) |
contract_name |
VARCHAR | 200 | NOT NULL | 合同名称 |
party_a |
VARCHAR | 100 | NOT NULL | 甲方(发包方) |
party_b |
VARCHAR | 100 | NOT NULL | 乙方(承包方) |
contract_amount |
DECIMAL | (18,2) | NOT NULL, DEFAULT 0.00 | 合同金额(元) |
sign_date |
DATE | — | NOT NULL | 签订日期 |
status |
TINYINT | — | NOT NULL, DEFAULT 0 | 状态:0-进行中,1-已完成,2-已终止 |
created_at |
DATETIME | — | NOT NULL | 创建时间 |
updated_at |
DATETIME | — | NOT NULL, ON UPDATE | 更新时间 |
字段设计要点:
contract_code使用 VARCHAR 而非 INT,支持“GC-2025-001”等业务编码格式。contract_amount使用 DECIMAL(18,2) 保证金额精度,避免浮点误差。status使用 TINYINT 枚举,预留扩展空间(如 3-待归档)。
3.3 合同主表建表 SQL(MySQL 示例)
CREATE TABLE `contract` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`contract_code` VARCHAR(50) NOT NULL COMMENT '合同编号',
`contract_name` VARCHAR(200) NOT NULL COMMENT '合同名称',
`party_a` VARCHAR(100) NOT NULL COMMENT '甲方',
`party_b` VARCHAR(100) NOT NULL COMMENT '乙方',
`contract_amount` DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '合同金额',
`sign_date` DATE NOT NULL COMMENT '签订日期',
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '状态:0-进行中 1-已完成 2-已终止',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_contract_code` (`contract_code`),
KEY `idx_sign_date` (`sign_date`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='合同主表';
3.4 字段设计决策对比
以下对比帮助理解关键字段的设计取舍:
| 决策点 | 方案A(选用) | 方案B(不推荐) | 理由 |
|---|---|---|---|
| 合同编号类型 | VARCHAR(50) + UNIQUE | INT AUTO_INCREMENT | 业务编号含前缀、年份,INT 无法表达语义 |
| 金额字段类型 | DECIMAL(18,2) | FLOAT / DOUBLE | DECIMAL 精确,避免浮点舍入误差 |
| 甲方乙方存储 | VARCHAR 直接存储名称 | 外键关联参与方表 | 主表高频查询,减少JOIN;参与方详情可冗余在子表 |
| 签订日期 | DATE 类型 | VARCHAR / INT | DATE 支持日期函数、索引、范围查询 |
避坑提醒: 不要将合同义务字段(如“付款节点”“验收日期”)直接放在合同主表中。义务是动态、多实例的,应单独建表,通过外键
contract_id 关联。主表只存合同级静态属性,否则后续义务跟踪将陷入字段爆炸与更新异常。