ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

仓库管理系统数据库设计:核心表结构与建表实操全解析

2026/9/8 6:44:01 拓冰建站 浏览量
仓库管理系统数据库设计:核心表结构与建表实操全解析 简介仓库管理系统的数据库设计资源面向数据库课程设计、毕业设计或中小型仓库项目开发者解决物资入库、出库、库存监控与采购流程的数据建模问题。压缩包共4个文件含Stock.sql脚本、Stock.mdf与Stock_log.ldf数据库文件、数据库系统原理课程设计说明书doc文档整体仅237KB结构精简。SQL脚本覆盖仓库、物资、库存、采购订单、入库记录、出库记录等核心表的建表语句包含字段定义、主外键关联及数据类型mdf/ldf为可直接附加的SQL Server数据库便于运行查看doc说明书对表结构、关系及设计思路做出系统梳理。资源可帮助读者快速理解规范化设计、事务一致性与权限控制等要点并可直接复用或改造为完整项目数据库。已有1369人学习适合需要快速上手数据库建模或完成相关课程设计的开发者。1. 仓库管理系统数据库设计从需求到建表一次讲清楚仓库管理系统WMS的数据库设计说白了就是把“货怎么进、怎么出、怎么盘点、怎么放在库房里”这些业务动作用一套表结构完整地记录下来。跟随手拿Excel记账不同数据库设计的好坏直接决定了系统后期能不能撑住多用户并发、能不能跑出准确的库存报表、能不能在盘点对账时省下大量人工时间。我在过去几年里接手过好几个仓库管理相关的项目从几万条数据的小型五金仓到日均出库过万单的电商仓都碰过。很多项目前期不重视表结构设计等到业务一复杂库存账对不上、单据流水查不清楚、并发扣减库存时超卖都是因为最底层的数据模型没搭稳。这篇内容就把我在实际项目中沉淀下来的一套通用仓库管理系统数据库设计思路连同每一步的理由整理出来供你参考。这套设计适合谁如果你是刚接触数据库设计的开发者课程作业或毕业设计正好选了这个题目照着这套表结构走不会踩大坑如果你已经在做中小型企业的管理类系统需要一套能覆盖进销存核心流程的数据模型同样可以直接借鉴。我会把每一张表的用途、字段怎么定、为什么这么定讲透而不是丢一堆建表语句让你自己猜。1.1 业务需求先拆明白仓库系统的核心动作有哪些任何数据库设计的第一步都不是急着建表而是把业务需求拆成“元事件”。仓库管理系统的核心业务其实可以归纳成几条主线商品信息维护仓库里存了什么货每种货有什么属性条码、规格、单位、批次、保质期。供应商和客户档案货从谁那里来卖给谁两套档案缺一不可。入库采购入库、退货入库、生产入库。入库是最重要的库存增量来源。出库销售出库、领料出库、退货出库。出库是库存减量的直接触发点。调拨/移库从A仓库挪到B仓库从普通库位移到拣货位库存在物理上发生移动。盘点周期性核对账面库存和实物库存产生盘盈盘亏结果。库存查询与报表实时查看当前可用库存、锁定库存、历史流水。顺着这些动作往后推你会发现它们的共同特征是每一笔业务都必须对应一条“凭证级数据”比如入库单、出库单商品的库存变动也一定要能追溯到具体是哪张单据产生的。这是进销存类系统数据库设计的第一原则——有据可查账实相符。我之前见过一个反面案例某团队图省事商品表里直接放一个stock字段每次入库出库就对这个字段做加减操作。前期数据量小的时候看起来一切正常后来发现出库单和库存数量对不上要反查是哪笔操作改错了结果根本没有任何流水表可以追溯最后只能靠月末盘点强行平账。所以设计时宁可表的数量多一点也要把流水记录完整保存下来。1.2 核心设计原则先搭骨架再填肉主数据与流水分离仓库系统表结构最适合采用“主数据 单据 明细”的三层模型。主数据层商品、供应商、客户、仓库、库位、用户。这些数据是相对稳定的基础档案。单据层入库单、出库单、盘点单、调拨单。每张单据是一个业务事件的头文件。明细层入库单明细、出库单明细、盘点单明细。一张单据对应多行明细记录具体商品和数量。为什么要分离主数据与单据因为主数据会变比如商品名称修改、供应商联系方式更新而单据一旦生成就是历史事实永远不能跟着“变”。假设商品表里的单位写错了连带把历史出库单里的单位也改了那整条数据链就乱了。真实做法是单据明细中冗余保存商品名称、规格、单位等关键“快照信息”哪怕商品主数据之后改了历史单据仍然记录着当时业务发生时的真实情况。再一个要点是头表和明细表分离。一张入库单有10种商品如果不用头表明细表的结构就只能传一个JSON串存到单个字段里查询统计时极其痛苦。头表明细表是进销存系统的经典范式不只是仓库系统几乎所有ERP、电商订单系统都这么设计。初学的时候可能觉得多写一张表很麻烦实际用起来才知道有多顺手统计某段时间内某商品的入库总量就是一条SUM语句的事。2. 全套表结构拆解13张表分别承担什么职责下面就是这套仓库管理系统数据库设计的核心表清单按模块划分你可以把它当作一份数据字典蓝图来用。表数量控制在13张左右已经能覆盖绝大多数中小型仓库的业务需求不至于因为表太少功能缺腿也不会因为表太多把设计搞得过于臃肿。2.1 主数据表商品、供应商、客户、仓库、用户先解决“基础档案从哪来”的问题。没有稳定干净的主数据后续所有单据都是空中楼阁。商品表product商品表是整个系统最基础的一张表字段设计上建议包含商品编码SKU、商品名称、类别ID、条码、规格型号、计量单位、默认采购价、默认销售价、安全库存、保质期天数、状态、备注、创建时间、更新时间。其中有两个字段我要特别强调。第一个是商品编码建议使用纯数字或“字母数字”的自定义编码而不是直接把自增主键暴露给用户。因为自增主键在系统迁移、数据合并时会不稳定而且从业务上说商品编码像人的身份证号一旦固定下来最好终身不变哪怕是商品改名了编码都不该变。第二个是条码字段在实际仓库作业中很多操作都依赖扫码枪快速识别商品条码字段建议设置为唯一索引并且要注意同一个商品可能存在多个条码一品多码如果有这种业务场景则需要额外建一张商品条码表。计量单位这里也容易出问题。常见的坑是“一箱12瓶”如果直接在商品表里写死一个单位那么入库时可能按箱录出库时按瓶发两个数字对不上。严谨的做法是设计单位换算关系比如建一张单位换算表或者至少在产品表上增加两个字段基本单位和换算系数。基础不太够的同学先从单单位开始做但心里要清楚这隐藏着一个业务边界。供应商表supplier和客户表customer这两个表的结构高度相似字段基本是编码、名称、联系人、电话、地址、开户行、银行账号、税号、状态、备注。很多人会问为什么不能合并成一张往来单位表其实可以不少进销存系统就是这么做的用类型字段区分是供应商还是客户。但中小型仓库系统我更倾向于拆成两张因为它们的业务统计维度不同拆开后SQL写起来更清晰也不需要到处加类型条件过滤。仓库表warehouse与库位表location仓库表相对简单仓库编码、仓库名称、负责人、联系电话、地址、状态。库位表要稍微复杂一点库位编码、仓库ID、库位类型收货暂存区、存储区、拣货区、退货区、是否锁定、创建时间。库位是仓库精细化管理的重要依据如果业务只到仓库级别不关心具体放在哪个货架那么库位表可以省略。但一旦仓库面积大、商品种类多有没有库位管理在找货效率上差别非常大。我强烈建议从设计初期就把库位字段预留下来哪怕前几个版本不用也免得后面大改表结构。用户表sys_user这对应了许多课程设计中“用户信息表”那一关。字段建议用户ID、用户名、密码MD5或bcrypt加密存储绝不能明文、真实姓名、手机号、邮箱、角色ID、部门、状态、最后登录时间、创建时间。密码字段强烈建议使用bcrypt/argon2而非简单MD5MD5在现在算力下一秒钟能暴力破解海量组合安全性太差。角色和权限的设计方式视项目复杂度而定。入门级做法是用户表里加一个角色字段比如“admin”“operator”“viewer”在代码里判断角色值来控制按钮可见性和接口权限。这种做法小项目够用再扩大可以考虑引入标准的RBAC模型用户-角色-权限三张核心表加关联表但那是另一个主题了这里不展开。2.2 单据表入库单、出库单、盘点单、调拨单单据表是业务事件的主记录。每种单据都有“主表一份 明细表多行”的结构。入库单stock_in_main与入库单明细stock_in_item入库单主表字段入库单号、入库类型采购入库/退货入库/盘盈入库/调拨入库、供应商ID若是采购、仓库ID、入库日期、制单人、审核人、审核状态、备注、创建时间。明细表字段ID、入库单ID、商品ID、商品名称快照、规格快照、单位快照、入库数量、入库单价、金额、生产日期、过期日期、批次号。主表上是不会直接放“金额”这个汇总字段的因为明细里已经有单价数量了汇总金额可以通过SUM推算。但如果你对查询性能有较高要求也可以在单据主表上冗余一个总金额字段每次生成单据时计算好存进去查询列表时不用再JOIN明细表做聚合。这种冗余在数据量大了以后性能优势明显代价是要保证写数据时计算正确。批次号和过期日期这两个字段很多人容易忽略。做食品、药品、化工类产品仓储时批次和效期是刚需没有它们做不了先进先出。如果只做五金标准件仓库这两个字段可以为空但建议保留在表结构里万一以后业务扩展不需要重建表。出库单stock_out_main与出库单明细stock_out_item出库单主表字段出库单号、出库类型销售出库/领料出库/盘亏出库/调拨出库、客户ID、仓库ID、出库日期、制单人、审核人、审核状态、备注。明细表字段和入库明细对称商品ID、出库数量、出库单价、金额、批次号、库位ID。特别注意出库单设计时要考虑“先进先出”还是“指定批次出库”。基础设计可以在明细表里直接放一个批次号字段这样既能按指定批次发货也能通过代码逻辑实现先进先出。如果不在明细表里记录批次那么同一商品不同批次进价不同卖出去后毛利算不准退货回来也不知道该退给哪一批。盘点单stock_take_main与盘点单明细stock_take_item盘点单主表字段盘点单号、仓库ID、盘点日期、盘点状态草稿/审核中/已完成、盘点人、审核人、备注。明细表字段盘点单ID、商品ID、账面数量、实盘数量、盈亏数量、备注。有一个容易被忽略的细节盘点明细里一定要同时存“账面数量”和“实盘数量”。因为盘点结果是要对比的如果只存实盘数量回头也查不出来当时系统里记录的账面数是多少等于失去了核对依据。我在做项目时还会额外在明细表里加一个“是否已经调整库存”的标记字段确认盘点结果无误并由主管审核之后再批量生成库存调整流水避免盘点单一保存就直接改库存万一后悔了都找不到回退的路径。调拨单stock_transfer调拨单字段调拨单号、调出仓库ID、调入仓库ID、调拨日期、状态、制单人、审核人、备注。调拨单明细商品ID、数量、批次号、调出库位、调入库位。调拨单设计上要注意一个原则一笔调拨业务在库存流水里应同时体现为“调出仓库的减少”和“调入仓库的增加”。很多入门设计会搞成两笔独立的出入库单来处理虽然账目上也能平但可追溯性差了很多——想看这笔货到底去哪儿了还得通过备注去关联两边的单子。2.3 核心库存表与流水账本库存的“家底”存在哪主数据表负责登记档案单据表负责记录事件这张表才是仓库账务的核心。库存表stock库存表字段设计ID、仓库ID、库位ID可选、商品ID、批次号、总库存量、锁定库存量、可用库存量、更新时间。这里最大的设计要点是把总库存量拆成“锁定库存”和“可用库存”两个概念。你可以这样理解总库存是仓库里实际躺着多少货锁定库存是已经被订单占用、还没真正出库的那部分可用库存才是销售员在界面上能看到并能承诺给客户的数量。比如一个商品总库存是100件客户A下单锁定20件那么可用库存就是80件。新的客户再下单时最多只能下80件不会超卖。等客户A那单真正发货出库总库存减20锁定库存也减20可用库存保持不变。如果不拆分这两个字段就只能在代码里用额外逻辑判断出库时是否够扣在并发场景下很容易出现超卖。而把两个字段放在库存表里每次更新都使用数据库的原子操作UPDATE stock SET locked locked 20 WHERE available 20超卖问题从数据库层面就能防住。库存流水表stock_log库存流水表是整套设计中我最看重的一张表它类似银行账户的交易明细。字段设计ID、仓库ID、商品ID、批次号、变动类型入库/出库/锁定/解锁/盘盈/盘亏/调拨、变动前数量、变动数量、变动后数量、关联单号比如入库单号/出库单号、操作人、创建时间。为什么要记录变动前数量这是为了事后审计时能看到每一笔操作的上下文。有了流水表哪天库存对不上直接查流水从期初数一路递推到最后马上能找到哪一笔变动异常。我还习惯在流水中加一个remark字段记录操作备注或单据号排查问题时能直接定位到原始单据。说实话如果只能从这套表结构里选一个“必须有的表”推荐给初学者我首推这张库存流水表。很多课程设计里的仓库系统没有流水表完全靠库存表单点更新那是纯粹的玩具系统验收时如果没有这个表一定要想办法说服自己补上。2.4 各表之间的关系一眼看懂外键与约束为了让你更直观地把握表与表之间的关联关系我画一张关系脑图式的文字描述放在这里——不用Mermaid你直接看文字对应关系即可入库单主表 1 —— N 入库单明细通过入库单ID关联出库单主表 1 —— N 出库单明细通过出库单ID关联供应商表 1 —— N 入库单主表通过供应商ID关联客户表 1 —— N 出库单主表通过客户ID关联商品表 1 —— N 库存表通过商品ID关联仓库表 1 —— N 库存表通过仓库ID关联入库单明细 N —— 1 商品表通过商品ID关联出库单明细 N —— 1 商品表通过商品ID关联盘点单主表 1 —— N 盘点单明细通过盘点单ID关联库存表 1 —— N 库存流水表通过商品ID仓库ID关联但流水表本身更建议独立记录外键约束在建表时我是建议加的保证引用完整性。但生产环境高并发场景下大量外键会影响写入性能常见做法是“逻辑外键”——不在数据库层面建FK约束而是在应用层保证关联。初学者课程设计建议加上外键因为评分老师看到外键关系会更认可你的设计严谨性做企业级系统则要把外键约束去掉改为索引应用层控制。3. 建库建表实操从零动手把数据库搭出来这一部分直接上能跑的SQL以MySQL 8.0为例。MySQL是目前中小型系统最常用的关系型数据库语法直观教程也多你要用PostgreSQL也可以逻辑不变。3.1 建库语句和字符集选择CREATE DATABASE IF NOT EXISTS wms_db DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;为什么特意指定utf8mb4而不是utf8因为utf8在MySQL里最多只能存3字节的字符像生僻字、部分特殊符号存不进去而utf8mb4是完整的4字节UTF-8编码兼容性更好。排序规则用utf8mb4_general_ci日常够用如果你对中文排序准确性有要求可以用utf8mb4_unicode_ci它在多语言排序规则上更准确代价是略慢一点点。3.2 核心建表SQL示例我抽几张代表性表给出完整SQL其余表结构同理。注意我统一使用了BIGINT主键因为INT最大约21亿看着挺大但含明细数的单据系统很容易在几年内达到千万级甚至上亿行没必要留这个隐患。CREATE TABLE product ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, sku VARCHAR(32) NOT NULL COMMENT 商品编码, name VARCHAR(200) NOT NULL COMMENT 商品名称, category_id BIGINT DEFAULT NULL COMMENT 分类ID, barcode VARCHAR(64) DEFAULT NULL COMMENT 条码, spec VARCHAR(100) DEFAULT NULL COMMENT 规格型号, unit VARCHAR(20) NOT NULL DEFAULT 件 COMMENT 基本单位, default_purchase_price DECIMAL(10,2) DEFAULT 0.00 COMMENT 默认采购价, default_sale_price DECIMAL(10,2) DEFAULT 0.00 COMMENT 默认销售价, safety_stock INT DEFAULT 0 COMMENT 安全库存, shelf_life_days INT DEFAULT NULL COMMENT 保质期天数, status TINYINT NOT NULL DEFAULT 1 COMMENT 1启用 0停用, remark VARCHAR(500) DEFAULT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_sku (sku), KEY idx_name (name), KEY idx_barcode (barcode) ) ENGINEInnoDB COMMENT商品表;注意几个细节条码字段建普通索引就够了唯一索引容易出问题——同一个SKU可能对应多个条码而且扫描枪偶尔读错码也可能会产生重复数据索引建太死反而不方便排查。金额字段一律用DECIMAL(10,2)千万不要用FLOAT或DOUBLE浮点数在二进制运算中有精度损失存金额会出现0.10.2不等于0.3的经典问题账目上这是致命的。CREATE TABLE stock_in_main ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, in_no VARCHAR(32) NOT NULL COMMENT 入库单号, in_type TINYINT NOT NULL COMMENT 1采购入库 2退货入库 3盘盈入库 4调拨入库, supplier_id BIGINT DEFAULT NULL COMMENT 供应商ID, warehouse_id BIGINT NOT NULL COMMENT 仓库ID, in_date DATE NOT NULL COMMENT 入库日期, creator BIGINT DEFAULT NULL COMMENT 制单人ID, auditor BIGINT DEFAULT NULL COMMENT 审核人ID, status TINYINT NOT NULL DEFAULT 0 COMMENT 0草稿 1待审核 2已审核 3已作废, total_amount DECIMAL(10,2) DEFAULT 0.00 COMMENT 入库总金额, remark VARCHAR(500) DEFAULT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_in_no (in_no), KEY idx_supplier (supplier_id), KEY idx_warehouse (warehouse_id) ) ENGINEInnoDB COMMENT入库单主表;入库单号这里我用UNIQUE KEY做了唯一约束。单号的生成规则建议用日期前缀加序列号比如IN20250512001含义是2025年5月12日第001号入库单。在应用层生成单号时要注意用数据库锁或Redis原子自增来防止并发生成重复单号这是很常见的作业系统踩坑点。CREATE TABLE stock ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, warehouse_id BIGINT NOT NULL, location_id BIGINT DEFAULT NULL, product_id BIGINT NOT NULL, batch_no VARCHAR(64) DEFAULT NULL COMMENT 批次号, total_qty INT NOT NULL DEFAULT 0 COMMENT 总库存量, locked_qty INT NOT NULL DEFAULT 0 COMMENT 锁定库存量, available_qty INT NOT NULL DEFAULT 0 COMMENT 可用库存量, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_warehouse_product_batch (warehouse_id, product_id, batch_no), KEY idx_product (product_id) ) ENGINEInnoDB COMMENT库存表;这张表最关键的是联合唯一索引(warehouse_id, product_id, batch_no)——同一个仓库里同一个商品同一个批次只允许一条库存记录。这个约束从数据库层面防止重复库存记录的产生非常关键。可用库存没有直接存在表里而是通过总库存减锁定库存算出来的这在更新时用一条SQL原子操作实现UPDATE stock SET locked_qty locked_qty #{qty} WHERE product_id #{pid} AND warehouse_id #{wid} AND available_qty #{qty}如果更新影响行数为0说明可用库存不足订单就不能继续处理。这段逻辑是先锁“额度”再减少“总库存”把并发扣库存问题解决在数据库层面。3.3 库存流水的自动记录思路每一笔影响库存的操作都要同时写一条库存流水。保证一致性的做法是在同一个数据库事务里执行更新库存表相应字段插入一条库存流水记录更新单据主表的状态例如把草稿改成已审核。三步在一个Transaction里要么全部成功要么全部回滚。很多库存对不上的问题不是业务规则错了而是更新库存和记录流水这两个步骤没有放在同一个事务中中间出了异常就出现“库存变了但流水没记”或者“流水记了但库存没变”的状态。用事务后这种状态基本就不会出现了。3.4 测试用例怎么设计数据正确性验证表建完后不能光看“能插入数据”要把它放到贴近真实的业务场景里验证。准备至少三组测试数据第一组是普通商品数量几十到几百第二组是同一商品的多个批次第三组是并发场景下高频率的出入库操作。用例覆盖入库10件后查库存是否10并发下同时下单锁定20件和锁定50件总可用只有60件时是否只有一个能成功盘点盈亏后流水变动是否前后对得上作废单据后库存是否自动回滚。初学阶段可能不太习惯写这种测试用例清单但养成这个习惯之后数据库设计的能力会明显提升一个台阶。建表完成只代表“结构对了”跑通业务场景并保证数据一致性才代表“设计真的对了”。4. 常见问题与排查技巧实录这一节整理我在实战中反复遇到的几个问题每个都踩过坑写出来给你避雷。4.1 中文乱码问题症状是前端页面数据显示正常但查数据库时看到中文变成了“???”或保存到库里变成乱码。原因是连接字符串里没有指定字符集或者在创建数据库时字符集不是utf8mb4。排查思路很简单——先确认数据库字符集再用命令行SHOW CREATE TABLE product;看表字符集最后看连接串是否配置了characterEncodingutf8三处都对上就不会乱码。4.2 自增ID用完或重置问题INT最大支持21亿听着很多但像库存流水这类高频表几年内就可能打满。处理方式一类表改用BIGINT另一类是清理归档历史数据后重置自增。重置时最直接的办法是ALTER TABLE stock_log AUTO_INCREMENT 1;但注意这个操作在有外键关联时可能报错生产环境要先评估影响。4.3 金额字段精度不准默认使用FLOAT类型存储金额的项目几乎都会在累计对账时发现小数位差异。用MySQL客户端执行SELECT 0.1 0.2;就能看到结果不是0.3。解决办法是全部金额字段改为DECIMAL(10,2)计算时避免在应用层用二进制浮点运算涉及累计的查询直接在SQL里用SUM完成。4.4 商品编码重复导致单据错乱没有唯一索引时应用层校验在多用户并发下形同虚设。两个管理员同时新增商品都填了同样的SKU,后插入的会覆盖先插入的。解决办法是给sku字段加上UNIQUE KEY数据库层面拦截。之前有用户问加上唯一索引后业务上真的会有重复编码需求怎么办那说明业务上这个字段设计本身有问题应该先调整业务规则。4.5 盘点导致库存被“改动”得不可追踪有些系统做完盘点直接更新库存表看起来数字好像对了但时间一长根本说不清楚库存是怎么变的。盘点正确流程是盘点单先保存实盘数量状态为草稿审核确认后再在同一事务中更新库存表并写入流水表流水里的变动类型标记为“盘盈”或“盘亏”。这样月末对账时能精确说出某次盘点调整了哪个商品、调整了多少、责任人是谁。4.6 慢查询排查的基本策略如果页面加载很慢优先用EXPLAIN SELECT ...;看执行计划。重点看是否走了索引。比如按出库单号查单据那在out_no字段上必须建索引按商品查流水在product_id上必须有索引。最笨但有效的排查方式把某条慢SQL拿出来单独执行加EXPLAIN看type列是不是ALL如果是ALL说明全表扫描了那就要考虑建索引了。5. 这套设计方案还能往哪些方向扩展如果你做完这套基础版还觉得不过瘾可以从下面几个角度扩展。支持多租户在企业SaaS场景下每家公司是独立租户核心业务表加一个tenant_id字段所有查询都强制带租户条件。批次与序列号管理除了批次号有些高价值商品还要做单件序列号追踪需要增加一张sales_serial表记录每个序列号从入库、出库到售后全程的位置。报表与数据仓库数据库设计完成后可以为统计分析建立独立的只读库定期用ETL同步业务库数据避免业务高峰统计查询影响正常单据操作。引入缓存层库存查询是高频读操作可以在Redis里缓存热门商品的库存数据写库时同步更新缓存降低数据库压力。但这属于架构层面的优化前期不需要做。从我的实际经验看仓库管理系统这类业务只要把主数据、单据、明细、库存、流水这五类表关系理清楚项目开发就成功了一多半。很多看似复杂的问题比如对账不平、超卖、历史追溯不了本质上都是因为底层数据模型没设计好。你可以先按这套结构把库建出来然后模拟走一遍采购入库、销售出库、盘点调整的完整流程感受一下数据是怎么流动的。动手敲一遍SQL比看十篇设计文章都管用。本文还有配套的精品资源点击获取