
本文讲解如何正确设计传输表,使一个主键值(如 transmittal_id)可关联多条记录,同时确保数据库完整性与业务逻辑一致。关键在于区分主键与业务标识,避免将业务编号误设为唯一主键。
本文讲解如何正确设计传输表,使一个主键值(如 transmittal_id)可关联多条记录,同时确保数据库完整性与业务逻辑一致。关键在于区分主键与业务标识,避免将业务编号误设为唯一主键。
在数据库设计中,“一个 transmittal_id 对应多行数据”是典型的一对多关系,常见于发货单、调拨单、传输单等业务场景。但需明确:主键(Primary Key)必须唯一且非空,因此不能直接将 transmittal_id 设为单一字段主键并允许重复——这会违反关系型数据库的基本约束。
✅ 正确做法是引入复合主键或代理主键:
方案一:使用代理主键(推荐)
为每行分配独立、无业务含义的自增 ID 作为主键,而将 transmittal_id 定义为普通字段(可重复),并搭配外键约束和索引提升查询效率:
CREATE TABLE transfer (
id BIGINT PRIMARY KEY AUTO_INCREMENT, -- 代理主键(唯一、非空)
transmittal_id INT NOT NULL, -- 业务单号,允许多行相同
product_id VARCHAR(20) NOT NULL,
product_name VARCHAR(100),
product_quantity INT NOT NULL,
-- 可选:添加外键指向主单头表(如 transmittal_header)
-- FOREIGN KEY (transmittal_id) REFERENCES transmittal_header(id),
INDEX idx_transmittal_id (transmittal_id) -- 加速按单号查询
);
插入示例:
INSERT INTO transfer (transmittal_id, product_id, product_name, product_quantity) VALUES (1, '220526', 'APCEE', 100), (1, '220524', 'LAGUNDI', 100), (1, '220529', 'TOVIT', 100), (1, '220601', 'BETTER C', 100), (1, '220605', 'ZINC VITA', 100);
查询某次传输的所有明细:
SELECT transmittal_id, product_id, product_name, product_quantity FROM transfer WHERE transmittal_id = 1;
方案二:复合主键(适用于无代理键场景)
若坚持不引入额外 ID,可将 (transmittal_id, product_id) 组合作为主键(前提是同一单内产品不重复):
CREATE TABLE transfer (
transmittal_id INT NOT NULL,
product_id VARCHAR(20) NOT NULL,
product_name VARCHAR(100),
product_quantity INT NOT NULL,
PRIMARY KEY (transmittal_id, product_id), -- 复合主键
INDEX idx_transmittal_id (transmittal_id)
);
⚠️ 注意事项:
-
NULL 不允许出现在主键列中——因此示例中首行 transmittal_id 为空(
)在严格主键约束下不可行;实际应用中应确保每行 transmittal_id 明确赋值。 - 若需支持“暂存草稿”状态(即未最终提交的单据),建议增设 status 字段(如 'draft'/'submitted'),而非留空主键字段。
- 为保障数据一致性,强烈建议建立单独的单头表(transmittal_header),存储单据元信息(如创建时间、操作人、状态),再通过外键关联明细表。
总结:transmittal_id 是业务维度的分组标识,不是技术主键。合理设计主键与索引,才能兼顾数据完整性、查询性能与业务扩展性。











