案例研究:微软 Northwind 数据库,从 Access 97 迁移到 SQL 和浏览器
Northwind 是微软随 Access 附带的示例数据库。我们使用它的一份公开副本(Access 97 格式),在一个任何人都能核查的文件上展示:我们如何把 Access 程序迁移到现代数据库,一行不丢,一个数字不变。这个页面背后没有客户,Northwind 中的公司和人物都是虚构的。

起点
- 一个 2,932 KB 的 Access 97 文件:9 张表共 4,032 行,22 个已保存查询(其中三个带参数,一个是交叉表),13 个报表和 21 个窗体。
- 以 OLE 对象存储的图片,只有 Access 能显示。
- 业务规则分散在字段属性、关系以及报表背后的查询中。
我们做了什么
- 数据。所有表和所有行都迁移到新的关系模式,以 SQLite 数据库和 PostgreSQL 脚本两种形式交付,包含主键、外键和索引,Access 的有效性规则也转为数据库约束。17 张图片逐像素转换为 PNG 文件。
- 查询。22 个已保存查询在两个数据库中都变成同名的 SQL 视图,报表所用的计算也一并迁移:折后订单合计、发票金额、按类别和年份统计的销售额。
- 验证。自动化测试把原始文件与新数据库进行比对:每张表的行数和每一行的校验和,以及每个查询的完整结果,共运行 855 次,并用四种方式核对(在原始文件上运行 Access SQL、一个独立模型、PostgreSQL 和浏览器)。
- 应用。基于迁移后数据库的网页应用,完全在浏览器中运行:订单及实时合计、客户、产品、供应商、员工、仪表板,以及可打印的原始报表。
运行结果
- 9/9
- 表格逐行一致
- 22/22
- 查询结果一致(运行 855 次)
- 17/17
- 违反规则的尝试被数据库拒绝
- $1,265,793.02
- 2,155 条订单明细的总值,在 SQLite、PostgreSQL 和浏览器中完全相同
两处差异,均为有意为之
Access 用二进制浮点数计算订单明细,并以近似值保存折扣(15% 存为 0.15000000596)。在 2,155 条订单明细中,有 18 条的精确金额恰好落在半分上,结果因此相差一分。新数据库保存精确的百分比,并在所有地方以相同方式舍入;总计变化 $0.16。所有受影响的明细都列在报告中。
148 个文本值去掉了末尾多余的空格或旧式换行符。其中一个是国家名 Sweden,有一次在末尾多存了一个空格,否则会被算作另一个国家。
测试过程中的发现
UCanAccess 是一款从 Java 读取 Access 文件的常用工具,它把这个 Access 97 文件中的折扣列读成整数,导致 838 个折扣全部变成零。表格核对发现了这个问题,报告中说明了我们如何做到同口径比对。Jackcess 重建的 SQL 文本还漏掉了某个查询的 TOP 10,我们从文件的系统表中读取了它。
该应用使用编译为 WebAssembly 的 SQLite,把 1,116 KB 的数据库加载到您的浏览器中。修改只保留在当前标签页,点击按钮即可恢复原始数据。