字段映射与类型:七种状态、四种日期与十二行失败

客户说「状态都是对的」,导入后看板却少了三列。七种状态压成四种、四种日期挤在一列、五十八个只有姓名的负责人,本文用一千二百四十行的矩阵,给出归一化、校验、失败行可下载三步,并说明 archived 为何不能直接算 done。

字段映射不是把两列对上,是把两种业务语义对上。

一、看板少了三列

何嘉树的任务板产品在九月接了一次竞品 A 的迁移,客户在邮件里写得很确定:「状态都是对的,直接导就行。」导入跑完的第二天,客户打开看板,第一句话是:「怎么少了三列?」他截图过来,原来七列并排的看板只剩四列,review 和 archived 整个消失,backlog 也不见了。

以下情境为教学假设,人物、引语和数字不代表经核实的真实案例。

他先把源文件拉出来逐列看。客户那边的七种状态拼写确实没毛病:backlog、todo、in_progress、review、blocked、done、archived,一个拼错的都没有。问题不在拼写,在目标。任务板只有四列:todo、doing、blocked、done。七个值塞进四个格子,必然有三次合并,而合并规则他从没和客户确认过。

客户的「状态都是对的」说的是值本身,不是语义。他把这句话翻译了一遍:这七个词在你的系统里有七个含义,在我的系统里只能落进四个格子,哪些词可以共用一个格子,得你点头。

按行数算,这次改写动了 214 行,占 1,240 行的 17.3%:in_progress 72 行、review 88 行、archived 54 行。剩下几种状态原样落进同名或近名的列,看起来「没动」,其实也经过了映射,只是映射是恒等的。

最疼的是 review。客户团队的习惯是「开发完了先放 review,等产品经理验收」。在原来那套看板里,review 是独立一列,站会时大家看的是「还有多少在等验收」。合并进 doing 之后,这一列消失了,产品经理只能逐条点开看。数字没错,视图没了。

他后来在复盘里写:映射不是翻译,是有损压缩。翻译追求一一对应,映射做不到;能做的只有两件事——把损失写下来,让客户在导入前签字。这句话后来成了他导入流程的第一条规则。

二、七种状态压成四种

映射表本身只有七行,但每一行背后都有一个要回答的问题:这个源状态在目标系统里到底意味着什么。他最后定下来的表是这样。

源状态目标状态是否改写判断依据
backlogtodo否(同义)都表示「还没开始」
todotodo否同名
in_progressdoing否(同义)都表示「正在做」
reviewdoing是已提交、未验收,仍在进行中
blockedblocked否目标系统保留了这个状态
donedone否同名
archiveddone是默认按「已结束」处理,需客户确认

review 归 doing 而不是 done,理由只有一个:done 在目标系统里的定义是「已验收交付」,而 review 是「已提交待验收」。如果把 review 算成 done,客户的周报会在验收前就把这些任务计进完成量,数字会好看,但会误导排期。宁可让看板少一列,也不能让「完成」这个词变味。

导入契约:十四列到十一个字段的验收表 里那条「状态字段必须附带枚举清单」的规定,就是这次事故之后加的。契约管的是格式,映射管的是语义,两件事不能互相替代。

archived 是唯一一个他没有直接下结论的状态。客户系统里的 archived 既可能是「做完归档」,也可能是「不做了关掉」,这两种含义在目标系统里应该落到 done 和「取消」两个完全不同的地方,而任务板当时没有「取消」。他没有替客户选,而是在预演报告里单独列了一行:archived 54 行,默认映射为 done,如其中有取消项请指出。客户回复说确实混着,最后把其中几行改成了关闭;这几行不在复算里,因为它是人工判断的结果,不是规则算出来的。

映射表要能反查。 每一行都要写清「为什么」,而不是只写「从 A 到 B」。半年后客户问「我的 review 去哪了」,能翻出这句话的人只有写表的人;写清楚,下一个接手的人才不用重新推。

默认值必须显式。 archived 落到 done 是默认,不是事实。默认值写在表里、写进预演报告、让客户确认,三步缺一步,默认就变成了偷偷决定。

不改写的行也要过一遍。 恒等映射看起来安全,其实最容易藏问题:源系统的 todo 可能允许空负责人,目标系统不允许,这一列在映射表上是「否」,在执行时仍然会失败。

三、四种日期与十二行失败

日期列是这次导入里最容易「看起来成功」的一段。1,240 行里混着四种写法,肉眼扫过去都是日期,程序读进去却是四种类型。

形态行数占比识别方式
ISO 860190172.7%形如 2025-03-14,直接解析
DD/MM/YYYY21417.3%带斜杠,按日/月顺序解析
Excel 序列号1139.1%纯数字,落在合理的日期区间内
Unix 秒121.0%十位整数,按时间戳换算

识别顺序不能靠猜,要写死:先匹配 ISO 的严格格式,再判断是否为 Excel 序列号,再判断是否为十位 Unix 秒,最后才按 DD/MM 解析。顺序换一下,结果就会变——一个十位整数既可以当成 Unix 秒,也可能被当成 Excel 序列号,只有把区间和位数都写进判据,才不会有第二种解释。

DD/MM 这一种最危险的不是格式,是歧义。03/04/2025 在一个地区是三月四日,在另一个地区是四月三日。他没有让程序去猜,而是在导入前的确认邮件里放了三行样例,请客户确认「日在前还是月在前」。客户的回复只有一句「日在前」,这一句话让 214 行免于整体偏移一天。

解析失败 12 行,占 0.97%。失败原因不是格式不认识,而是值本身不成立:有的月份写了 13,有的日期是 2 月 30 日,还有几行是「待定」「下周」这类自然语言。这 12 行没有被静默丢弃,也没有被填成当天,而是进了失败清单,等客户逐条给值。

负责人这一列有两副面孔。1,182 行是邮箱,58 行只有姓名,加起来正好 1,240。邮箱可以直接对上账号;只有姓名的要靠匹配,51 行匹配成功,占 58 行的 87.9%,剩下 7 行建了占位账号,标记为「待认领」,等客户在设置页里绑定。

匹配之前先归一化:去首尾空格、全角转半角、大小写统一、连续空格压成一个。姓名的匹配还多一步 Unicode 规范化,否则同一个字的两种写法在字节层面不相等,看起来一样的两个名字会匹配失败。

失败清单固定四列:行号、字段、原因、原文。客户下载下来就是一张能直接改的表,改完重传,只跑失败的那几行。清单里不放内部字段名,也不放堆栈,客户看不懂的东西一律不出现。

列写什么不要写什么
行号源文件里的物理行号程序内部的循环下标
字段用户能认出的列名数据库的列名
原因一句话,说明为什么不收异常类名与堆栈
原文该行该列的原始值被截断或改写后的值

四、先归一化,再校验,最后写库

类型问题看起来零散,处理次序却只有一条:先归一化,再校验,最后才写库。顺序颠倒,前面两步就白做。

归一化负责把「同一种东西的不同写法」收成一个;校验负责判断收完之后是否合法;写库只接受已经合法的值。很多实现把三步揉在一起,解析的同时就插入,一旦某行失败,事务里已经躺了半条记录,回滚和重试都变得麻烦。

复算:这次映射的规模与失败率放在一起看。

状态 7 → 4:backlog/todo→todo、in_progress/review→doing、blocked→blocked、done/archived→done
改写 72 + 88 + 54 = 214 行 = 214 ÷ 1,240 = 17.3%
日期 4 种:ISO 901(72.7%)+ DD/MM 214(17.3%)+ Excel 113(9.1%)+ Unix 12(1.0%)
解析失败 12 行 = 12 ÷ 1,240 = 0.97%
负责人:邮箱 1,182 + 仅姓名 58 = 1,240;姓名匹配 51 = 51 ÷ 58 = 87.9%

1,240 行 × 14 列 = 17,360 格,其中空值 2,914 格,占 16.8%。空值不是错误,但必填三列的空是:缺失 7 行,占 0.56%。这三列必须在契约里写死,导入器才有权拒绝整行,而不是替用户填一个空字符串。

映射与类型这一段,在人工代导入的 270 分钟里对应的是清洗的 90 分钟。90 分钟不算长,但它决定了后面 120 分钟的执行会不会返工:映射表错一行,执行完再改,就得整批重来。

去重与合并:八十六行重复、两种判据与一次误合并 会接着处理「同一行进来两次」的问题。两件事的边界很清楚:本篇保证一行进来之后含义正确,去重保证同一行不会进来两次。

失败行必须可下载,这一条没有例外。不能下载的失败清单等于没有清单,客户只能拿着截图来找你,你只能打开数据库一条条查。清单的格式也要稳定,列名和顺序不要随版本变,客户可能已经写好脚本在处理它。

写库之前还有一道检查容易被跳过:把映射后的分布打出来,和目标系统的枚举对一遍。七个源状态应该变成四个目标状态的某个分布,如果某个目标状态是 0 行,先别高兴,很可能是映射写错了一个分支。

五、行动清单与复算验收

八条按「先列表、再定判据、最后留证据」的顺序做,一个人半天能做完第一版。

  • 导出源系统的全部枚举值,逐个数清,不靠记忆。
  • 为目标系统的每个状态写下语义定义,一句话,可被客户读懂。
  • 出一张七行的映射表,每行写「是否改写」与判断依据。
  • 把有歧义的映射(如 archived)单独列出,请客户书面确认。
  • 为日期列写死识别顺序,并对歧义格式取样例请客户确认。
  • 负责人先归一化再匹配,匹配不上的建占位并标记待认领。
  • 失败清单固定四列,可下载、可重传、可只重跑失败行。
  • 写库前打印映射后的分布,与目标枚举逐项对数。

清单可以压成一句话:值要归一,义要确认,错要留痕。三件事里最容易被省掉的是第二件,因为它需要客户回一句话,而代码不会因为你没问就报错。

验收标准:任取一行导入后的任务,都能说出它来自哪个源值、经过了哪条映射、为什么落到这个目标值;说不出来就是映射没做完。

使用边界与实操验收

边界一:不替用户猜业务语义。 archived 是否等于 done、review 是否算完成,这些是客户的业务定义,不是技术选择。导入器可以提供默认值,但默认值必须被看见、被确认。

边界二:本篇不做 schema 迁移。 表结构怎么加列、怎么回填、怎么双写,属于架构组的范围;本篇只处理「值从一种表示变成另一种表示」。

边界三:本篇不涉及法定导出与删除。 数据可携带权下的导出格式、删除请求的响应时限,按隐私组的口径执行,映射表不能替代那些义务。涉及法定权利时以适用法域与专业意见为准。

边界四:本篇不做去重与合并。 一行进来两次是下一篇的问题;本篇的判据只保证单行含义正确,不保证集合唯一。

边界五:映射不承诺无损。 七变四一定有信息损失,能做的是把损失写明、让客户签字,而不是假装四个格子能装下七种含义。金额、税率、时区这类高风险字段,映射后必须抽样人工核对,不能只看程序报成功。

关键参考与核验范围

以上链接于 2026-10-26 实测可公开访问;未核验版本、价格与配额。核验日期:2026-10-26。

本文的映射表、日期分布与失败率来自一个 1,240 行的教学样例,不代表任何具体产品的导入行为。不同产品的状态枚举、日期默认格式与负责人模型都不同,落地前应以目标系统的官方文档为准;涉及语义判断的部分,以客户书面确认为准。

系列导航

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「Indie」更多文章

  1. 开源项目验收:十项能力、四维评分与三种不该开源的项目
  2. 治理、fork 与退出:17 位贡献者、82% 的提交与一次改协议的代价
  3. 双许可与企业版:九家询价、两家成交与 4,800 美元