返回

CSV 按主键比较

数据互转

正在载入

正在加载工具

工具代码会在打开时按需载入,请稍候。

本工具的全部运算都发生在你的浏览器中,输入内容不会发送到任何服务器。

关于这个工具

按能标识记录的列比较两份 CSV 快照,而不是逐行对齐文本。粘贴内容或选择本地文件,再指定双方共有的一个主键列,或多个列组成的复合主键。报告分别统计新增、删除、变化和未变化的行,列出新增与删除的列,并展示单元格前后值。适合订单导出和仓库库存快照等场景:只改变排序,不应被当成大量记录修改。解析与比较在可终止的浏览器工作线程中本地运行;本工具不上传或持久保存输入。

常见用途

  • 按 order_id 核对前后两份订单导出,查找新订单、删除记录和状态或金额文本的变化。
  • 按 warehouse 与 sku 组成的复合主键比较库存,让不同仓库中的同一商品保持为独立记录。
  • 区分 CSV 列结构变化与行内容变化,再保存保留原始字符串的 JSON 报告或长格式差异 CSV。

使用方法

  1. 1.粘贴比较前、比较后的 CSV,或分别选择本地文件。每边独立选择逗号、分号、制表符或竖线分隔符,并确认首行是否为表头。按需选择文件编码;支持 UTF-8、UTF-16LE 和 UTF-16BE。 先运行列检查,再查看可用列,选择两边均存在且名称完全一致的一个或多个主键列。关闭表头时使用自动生成的 column1、column2 等列名。复合主键把所选值组合使用,每个完整组合在每边至多对应一行。
  2. 2.默认保持字符串精确比较;仅在确有需要时启用去除首尾空白或忽略大小写。这两项同时影响主键匹配和单元格相等判定,不改变表头。默认拒绝任一主键分量为空;仅在空值有明确含义且仍能唯一标识记录时主动允许。 运行比较,检查行统计、新增与删除列,以及单元格差异。先修复重复主键或解析诊断,再重试;存在歧义时不会生成部分匹配。需要时可取消任务。修改输入或比较设置会使旧结果失效。
  3. 3.下载 JSON 报告以保留原始单元格字符串,或导出含 kind,key,column,before,after,before_present,after_present 列的差异 CSV。key 字段为 JSON 数组。用于电子表格时保留公式防护;只有确认警告及目标软件行为后才选择原始导出。 屏幕筛选和缩略预览不会删减导出数据。

可复现的主键比较示例

订单状态变化与行顺序调整

{
  "before": "order_id,status,total\n001,pending,12.50\n002,paid,0\n003,paid,7",
  "after": "order_id,status,total\n003,paid,7\n001,paid,12.50\n004,pending,5",
  "beforeOptions": {
    "delimiter": ",",
    "header": true
  },
  "afterOptions": {
    "delimiter": ",",
    "header": true
  },
  "compareOptions": {
    "keys": [
      "order_id"
    ],
    "trim": false,
    "ignoreCase": false,
    "emptyKeys": "reject"
  }
}
{
  "summary": {
    "added": 1,
    "removed": 1,
    "changed": 1,
    "unchanged": 1,
    "cellsChanged": 1
  },
  "columnsAdded": [],
  "columnsRemoved": []
}

选择 order_id 作为主键。订单 004 新增、002 删除、001 的状态改变,003 未变化。调整行顺序不会产生额外差异;示例输出为简要统计。

仓库与 SKU 组成的库存复合主键

{
  "before": "warehouse,sku,qty,note\nNorth,A,10,\"ready, packed\"\nSouth,A,5,\"line 1\nline 2\"\nNorth,B,8,hold",
  "after": "sku,warehouse,note,qty\nA,South,\"line 1\nline 2\",6\nA,North,\"ready, packed\",10\nC,North,new,4",
  "beforeOptions": {
    "delimiter": ",",
    "header": true
  },
  "afterOptions": {
    "delimiter": ",",
    "header": true
  },
  "compareOptions": {
    "keys": [
      "warehouse",
      "sku"
    ],
    "trim": false,
    "ignoreCase": false,
    "emptyKeys": "reject"
  }
}
{
  "summary": {
    "added": 1,
    "removed": 1,
    "changed": 1,
    "unchanged": 1,
    "cellsChanged": 1
  },
  "columnsAdded": [],
  "columnsRemoved": []
}

同时选择 warehouse 和 sku。South/A 的数量从 5 变为 6,North/B 删除,North/C 新增,North/A 未变化。表头顺序调整不影响匹配;带引号的逗号和多行备注均作为单元格内容解析。

按精确表头名匹配调换的列

{
  "before": "id,name\n1,Alice",
  "after": "name,id\nAlice,1",
  "beforeOptions": {
    "delimiter": ",",
    "header": true
  },
  "afterOptions": {
    "delimiter": ",",
    "header": true
  },
  "compareOptions": {
    "keys": [
      "id"
    ],
    "trim": false,
    "ignoreCase": false,
    "emptyKeys": "reject"
  }
}
{
  "summary": {
    "added": 0,
    "removed": 0,
    "changed": 0,
    "unchanged": 1,
    "cellsChanged": 0
  },
  "columnsAdded": [],
  "columnsRemoved": []
}

name 和 id 的位置互换,但列名和值均未改变。启用表头时,该行仍为未变化。

保留前导零与小数字面写法

{
  "before": "id,code,total\n001,007,1.0",
  "after": "id,code,total\n001,7,1",
  "beforeOptions": {
    "delimiter": ",",
    "header": true
  },
  "afterOptions": {
    "delimiter": ",",
    "header": true
  },
  "compareOptions": {
    "keys": [
      "id"
    ],
    "trim": false,
    "ignoreCase": false,
    "emptyKeys": "reject"
  }
}
{
  "summary": {
    "added": 0,
    "removed": 0,
    "changed": 1,
    "unchanged": 0,
    "cellsChanged": 2
  },
  "columnsAdded": [],
  "columnsRemoved": []
}

所有值都按字符串处理。主键 001 的 code 从 007 变为 7,total 从 1.0 变为 1,因此该行有变化。工具不会将它们自动转为数字,也不会执行财务计算。

空单元格也保留列结构变化

{
  "before": "id,old\n1,",
  "after": "id,new\n1,",
  "beforeOptions": {
    "delimiter": ",",
    "header": true
  },
  "afterOptions": {
    "delimiter": ",",
    "header": true
  },
  "compareOptions": {
    "keys": [
      "id"
    ],
    "trim": false,
    "ignoreCase": false,
    "emptyKeys": "reject"
  }
}
{
  "summary": {
    "added": 0,
    "removed": 0,
    "changed": 1,
    "unchanged": 0,
    "cellsChanged": 2
  },
  "columnsAdded": [
    "new"
  ],
  "columnsRemoved": [
    "old"
  ]
}

old 列被删除,new 列被新增。不存在的列与存在但值为空字符串的列不同,因此匹配行仍标为变化。这是结构差异,不会猜测列重命名。

主动启用去除首尾空白与忽略大小写

{
  "before": "id,status\n A , Paid ",
  "after": "id,status\na,paid",
  "beforeOptions": {
    "delimiter": ",",
    "header": true
  },
  "afterOptions": {
    "delimiter": ",",
    "header": true
  },
  "compareOptions": {
    "keys": [
      "id"
    ],
    "trim": true,
    "ignoreCase": true,
    "emptyKeys": "reject"
  }
}
{
  "summary": {
    "added": 0,
    "removed": 0,
    "changed": 0,
    "unchanged": 1,
    "cellsChanged": 0
  },
  "columnsAdded": [],
  "columnsRemoved": []
}

同时启用两项后,主键与 status 均比较相等。JSON 报告仍保留原始大小写和首尾空白。这两项设置不改变表头匹配规则。

拒绝无法唯一匹配的重复主键

{
  "before": "id,name\n1,Alice\n1,Bob",
  "after": "id,name\n1,Alice",
  "beforeOptions": {
    "delimiter": ",",
    "header": true
  },
  "afterOptions": {
    "delimiter": ",",
    "header": true
  },
  "compareOptions": {
    "keys": [
      "id"
    ],
    "trim": false,
    "ignoreCase": false,
    "emptyKeys": "reject"
  }
}
{
  "error": "duplicateKey",
  "side": "before"
}

比较前的两行都使用主键 1。工具会停止比较并给出重复主键诊断,不会任意选取 Alice、Bob 或第一行、最后一行。

用不同分隔符比较无表头文件

{
  "before": "001;alpha\n002;beta",
  "after": "001|alpha\n003|gamma",
  "beforeOptions": {
    "delimiter": ";",
    "header": false
  },
  "afterOptions": {
    "delimiter": "|",
    "header": false
  },
  "compareOptions": {
    "keys": [
      "column1"
    ],
    "trim": false,
    "ignoreCase": false,
    "emptyKeys": "reject"
  }
}
{
  "summary": {
    "added": 1,
    "removed": 1,
    "changed": 0,
    "unchanged": 1,
    "cellsChanged": 0
  },
  "columnsAdded": [],
  "columnsRemoved": []
}

比较前选择分号,比较后选择竖线,并为两边关闭表头。以自动生成的 column1 为主键,002 删除、003 新增,001 未变化。

常见比较误区

  • 同一商品在不同仓库各有一行,却只选择 sku 作为主键。
  • 分隔符或表头选项错误,仍从解析错误的列中选择主键。
  • 忽略字符串比较规则,把 001 与 1、1.0 与 1 当成相同。
  • 开启大小写或首尾空白规范化后,未检查原本不同的主键是否发生冲突。
  • 把标识符变化理解为原行修改,或期待自动识别列重命名。
  • 用电子表格打开不可信的原始差异 CSV,或分享前未检查导出内容中的私密信息。

限制与说明

  • 每边文件字节与解码后文本的 UTF-8 字节均不得超过 2 MiB,另限 10,000 个数据行、128 列和 200,000 个单元格;单次导出上限为 12 MiB。工作线程设有时限并支持取消,超过限制会停止操作。更大的快照可按主键范围分片后成对比较,或使用本地数据库、数据处理工具。工作线程时限并非严格的内存沙箱。 文件必须能严格解码为 UTF-8、UTF-16LE 或 UTF-16BE。BOM 必须与所选编码一致,并在解析前移除。处理 BOM 不代表支持 GBK、Shift_JIS 等旧编码,请先重新导出为受支持编码。分隔符需明确选择;错误引号和行宽不一致会被拒绝,不会自动修补。 屏幕每页显示 25 行,每行最多展示 12 个单元格和 6 个主键分量,并缩略较长的值。完整内容请查看导出报告。
  • 表头按名称精确匹配,不受列顺序影响;空白或重复表头会被拒绝。忽略大小写或空白的选项不会规范化、重命名表头。无表头时,column1、column2 等名称代表位置,调换列顺序会改变其含义。 新增或删除列属于结构变化,因此匹配行即使相关单元格为空,也可能标为变化。不会推断列重命名;主键改变会表现为删除一行并新增一行。行顺序本身不参与比较。
  • 任一边存在重复完整主键都会停止比较,包括去除首尾空白或忽略大小写产生的冲突。不会猜测取第一行、最后一行或多对多匹配。默认拒绝所选主键中任一分量为空;主动允许空值也不会关闭重复键检查。 所有单元格始终是字符串:001 不同于 1,1.0 不同于 1。去空白仅去除首尾空白;忽略大小写不提供模糊匹配、Unicode 规范化、语言区域排序或数值容差。不会计算日期、数字或公式。
  • JSON 在启用相等判定选项后仍保留解析所得的原始字符串,但不是源文件的逐字节副本。差异 CSV 是长格式变化报告,不是合并后的表格或可直接导入的补丁。安全导出会在类似公式的字段前加单引号,因而改变其导出文本。原始导出可能触发表格公式;CSV 引号本身无法防护,各表格软件也可能以不同方式解释数据。 before_present 与 after_present 字段区分缺失单元格和空字符串。在表格软件中保存后重新打开,单引号防护可能被移除;不存在对所有软件都绝对安全的 CSV 导出。 差异 CSV 每个受影响单元格占一条记录,新增或删除行会包含其中每个现有单元格;未变化行仅保留在 JSON 中。JSON 用 null 表示缺失单元格,而文本 null 仍是字符串。 对于没有数据行的表,仅有列结构变化时,差异 CSV 不会产生单元格记录;请用 JSON 保留完整列元数据。
  • 内容以文本显示,不运行 HTML、脚本或公式。输入与结果留在页面内存中,直到清空或关闭页面;本工具不添加上传或持久存储。下载的报告可能包含私密数据,离开页面后不受页面控制。

常见问题

怎样选择主键并处理重复主键错误?

选择两边共有、能唯一标识一条记录的列。订单可使用 order_id,分仓库存可组合 warehouse 与 sku。排序后临时生成的行号通常不适合作为主键,因为下次导出时可能对应另一条记录。 同一主键对应多行时,无法唯一确定配对关系。诊断会标明受影响的一边及从 1 开始的数据行号。解析错误使用包含表头的 CSV 记录号;带多行字段时,记录号可能不同于物理行号。补选缺失的主键列,或明确整理源数据的重复记录后重试。去除首尾空白和忽略大小写也可能让原本不同的键产生冲突。

两份文件可以使用不同分隔符、列顺序或编码吗?

可以,两边输入设置相互独立。例如可比较 UTF-8 逗号分隔文件与受支持的 UTF-16 制表符分隔文件。有表头时,即使列顺序不同,也按精确列名匹配;不会翻译、去除表头空白或推断改名。

忽略大小写或空白会修改原始数据吗?

只改变相等判定与主键匹配。JSON 的前后值仍保留解析所得原始字符串。这些选项也作用于主键单元格,请检查是否因此产生冲突。表头仍必须精确一致。

哪种导出能保留原始值与缺失单元格的区别?

需要保留原始字符串和结构区别时选择 JSON。差异 CSV 用长格式记录变化,主键以 JSON 数组表示。用于电子表格时请保留单引号公式防护。原始 CSV 保留单元格文本,但可能被解释为公式,仅适用于你已评估的目标系统。 空字符串是现有列中的一个值;缺失列是表结构差异。报告保留该区别,列出新增或删除列,并把匹配行中受影响的单元格记入变化,不会悄悄将两者视为相等。

相关工具