双表差异对账
回答一个高频且要命的问题:这两份表,到底哪里不一样?
适用场景:财务对账、银行流水核对、库存盘点、名单比对(报名 vs 到场)、改版前后数据校验、系统迁移后的一致性验证、月度报表与上月的差异。
通用数据清洗技能只处理单表,不做跨表比对。人工核对几千行既不现实也容易漏。本技能把这件事变成一条命令。
何时使用
- 用户说"这两个表对不上,帮我看看差在哪"
- 用户说"这版数据比上一版改了什么"
- 用户说"盘点结果和系统库存差了多少"
- 用户说"名单 A 和名单 B 有哪些人不一样"
快速试用(含样例)
技能包自带一份可复现的样例,位于 examples/。首次使用时可直接跑一遍验证环境:
python scripts/diff_tables.py examples/table_a.csv examples/table_b.csv -o examples/diff_report.xlsx
样例模拟"上月 vs 本月"订单对账,8 行 vs 7 行,埋入主键格式差异(ORD-00001 vs ord00001)、浮点误差、列顺序打乱三类陷阱。预期结果:未变更 3 / 修改 2 / 新增 2 / 删除 3。逐项校验见 examples/README.md。
执行步骤
- 确认两份文件的路径、主键列(如订单号、身份证号、商品编码)。
- 如果用户没指定主键,先尝试自动推断并告知用户推断结果,请求确认后再执行。主键选错会导致结果完全错误,这一步不能跳过。
- 运行比对,输出 Excel 报告。
- 向用户汇报:新增多少、删除多少、改了多少、哪些字段改动最集中。
用法
python scripts/diff_tables.py "A表.csv" "B表.csv" -k "订单号" -o "对账结果.xlsx"
多列联合主键:
python scripts/diff_tables.py A.csv B.csv -k "日期,门店,商品编码" -o diff.xlsx
只比对关心的列(忽略无关字段,减少噪音):
python scripts/diff_tables.py A.csv B.csv -k "订单号" --compare "金额,数量,状态" -o diff.xlsx
常用参数
| 参数 | 说明 |
|---|---|
-k, --key |
主键列名,多列用英文逗号分隔。强烈建议显式指定 |
-o, --output |
输出 xlsx 路径,默认 diff_result.xlsx |
--compare |
只比对指定列,默认比对全部列 |
--ignore |
忽略指定列(与 --compare 二选一) |
--tolerance |
数值容差,默认 1e-9。两数差的绝对值小于该值视为相同 |
--no-normalize |
关闭主键归一化(默认开启) |
--sheet-a / --sheet-b |
读取 xlsx 时指定工作表名 |
--no-header |
输入文件无表头行 |
--top |
控制台摘要里显示改动最频繁的字段数量,默认 5 |
主键归一化(默认开启)
真实数据里,主键"看起来不一样但其实是同一个"的情况极常见。归一化会依次处理:
- 去除首尾空白与所有内部空白
- 全角数字字母转半角
- 英文统一大写
- 去除常见分隔符
-_空格(仅对长度 ≥ 8 的纯数字字母串生效,避免误合并)
这样 A-001、a001、A001 会被识别为同一条记录,而不是报成"删除一条 + 新增一条"。
输出报告
Excel 报告包含 4 个工作表:
| Sheet | 内容 |
|---|---|
| 摘要 | 两侧行数、新增/删除/修改/未变更数量、改动最频繁的字段排行 |
| 新增 | 在 B 表但不在 A 表的行 |
| 删除 | 在 A 表但不在 B 表的行 |
| 修改 | 逐字段列出:主键值、字段名、A 表值、B 表值 |
控制台输出示例
A 表 : 1250 行 B 表 : 1247 行
主键 : 订单号(已归一化)
比对结果
未变更 1198 行
已修改 34 行(涉及 61 个单元格)
新增 15 行
删除 18 行
改动最集中的字段
1. 状态 22 处
2. 金额 19 处
3. 收货地址 14 处
警告:A 表中存在 3 个重复主键,已保留首次出现;建议先确认数据唯一性。
已输出:对账结果.xlsx
限制
- 两份表的表头需基本一致;列名不同的列会被视为"仅存在于单侧",记录在报告中但不参与比对。
- 主键重复时默认保留首次出现的行,并在报告中给出警告。
- 全量内存处理,建议单表不超过 50 万行。
- 比对结果反映的是当前两表的静态差异,不代表哪一方是正确值。
依赖
仅使用 Python 标准库。读写 .xlsx 需要 openpyxl:
pip install openpyxl