ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Access数据分析实战:从Excel迁移到关系型查询的完整指南

Access数据分析实战:从Excel迁移到关系型查询的完整指南

简介:《Access 2007数据分析技巧详解》面向希望借助关系型数据库提升数据处理能力的中级用户,尤其适合已熟悉Excel、但在数据量增长后遇到扩展性与分析透明度瓶颈的读者。全书由微软认证应用程序开发师迈克尔·亚历山大撰写,先对比Access与Excel在可扩展性、数据与呈现分离、数据结构演变及共享处理上的差异,再讲解表创建、数据类型、数据导入与查询基础,并深入聚合查询、制表/删除/追加/更新等操作查询及交叉表查询的用法,同时覆盖查找删除重复记录、填充空白字段、字段连接、文本与大小写转换、去除首尾空格、查找替换等数据转换任务。资源包为1个PDF文件,约11.35MB,内容完整、便于离线查阅。已有80人学习,适合作为查询设计与数据清洗的案头参考。

1. 从一份 2007 年的 Access 数据分析手册说起:它到底能解决什么

手里有一批业务数据,几十万行,字段十几个,Excel 打开就卡,透视表刷新一次要等半分钟,公式一多直接假死——这种场景下很多人第一反应是上 Python 或者 BI 工具,但如果你手上只有 Office,其实还有一条被低估的路:把数据丢进 Access,用查询层做清洗和聚合,最后再把结果导回 Excel 出图。这份《Access 2007 数据分析》讲的就是这条路子,作者是微软认证应用程序开发师,全书围绕「为什么用 Access 做分析」「表怎么建」「查询怎么写」「脏数据怎么转」四个层次展开,核心论点很明确:Access 在可扩展性、分析过程透明度、数据与呈现分离、数据量上限、结构约束、共享处理这几个维度上,比单纯用 Excel 更适合承载中等规模的分析任务。

它适合两类人:一类是天天和 Excel 打交道、数据量已经顶到天花板的业务分析人员;另一类是刚接触关系型数据库、需要一个能立刻上手的关系型数据库查询技巧练手环境的新手。不适合指望它讲 Power Query、DAX 或者现代数据栈的人——这是 2007 年的东西,工具链是老的,但查询逻辑、数据转换思路、关系建模的基本功不过时。下面按「资源是什么 → 怎么用 → 坑在哪」的顺序拆。

2. 为什么选 Access 而不是 Excel:八个维度的选型账

2.1 数据量与可扩展性的真实边界

Excel 2007 的单表上限是 1048576 行、16384 列,听起来够用,但实际卡死你的不是行数上限,是公式重算和透视缓存的性能。一份 30 万行、20 列的明细表,加几个 VLOOKUP 和 SUMIFS,文件就能膨胀到几十兆,每次改一个单元格全表重算。Access 的单表理论上限是 2GB 文件大小(Access 2007 的 ACCDB 格式),实际单表能扛到百万行级别,关键是它把存储和计算分开了:数据落在表里,计算发生在查询执行时,不会因为改一个字段触发全表重算。

书里给的判断标准我整理成一张表,方便你对照自己的场景:

维度Excel 更合适Access 更合适
数据量几万行以内十万到百万行
分析过程一次性、临时性需要反复跑、要留痕
数据与呈现混在一起无所谓要求分离,报表可重生成
数据结构扁平、单表多表关联、有主外键
数据演变静态快照持续追加、需要历史
功能复杂度简单聚合多步查询、操作查询
共享处理单人多人共用同一数据源

这张表不是让你二选一,而是告诉你什么时候该把数据从 Excel 挪到 Access。我的经验是:当你发现自己在 Excel 里反复做同一套清洗动作超过三次,就该考虑迁到 Access 用查询固化下来。

2.2 关系型建模:表结构决定后面所有查询的难度

Access 是关系型数据库,建表不是把 Excel 列照搬过去就完事。书里强调的第一件事是主键和数据类型:每张表要有一个唯一标识(自动编号或业务主键),字段类型要按实际语义选(日期就是日期型,别用文本存「2024-01-01」),否则后面查询里的日期函数、排序、比较全都会出问题。

一个典型的翻车场景:从 Excel 导入时,金额列里混了「1,234.56」这种带千分位的文本,Access 导入时会把它识别成文本型,之后你写SUM(金额)得到的是 0 或者报错。正确做法是导入前在 Excel 里把该列转成纯数字,或者在 Access 里建一个转换查询先清洗再入表。

建表时还要想清楚一对多关系。比如订单表和订单明细表,订单表主键是订单号,明细表里订单号是外键,两张表通过「关系」窗口建立一对多关联,并且勾选「实施参照完整性」。这一步不做,后面写连接查询时会出现孤儿记录,聚合结果对不上。

2.3 查询基础:从选择查询到聚合查询的递进

Access 的查询分几层:选择查询(筛选列和行)、聚合查询(GROUP BY)、交叉表查询(行转列)、操作查询(生成表、删除、追加、更新)。书里的编排是先讲选择查询,再讲聚合,最后讲操作查询和交叉表,这个顺序是对的,因为后面的都建立在前面之上。

一个最基础的选择查询,在 SQL 视图里长这样:

-- 从订单明细表里筛出 2024 年之后、金额大于 1000 的记录 SELECT 订单号, 产品ID, 数量, 单价, 数量 * 单价 AS 金额 FROM 订单明细 WHERE 下单日期 >= #2024-01-01# AND 数量 * 单价 > 1000 ORDER BY 金额 DESC;

逻辑说明:#...#是 Access SQL 的日期字面量写法,和标准 SQL 的单引号不同,这是 Access 特有的语法坑;数量 * 单价 AS 金额是计算字段,Access 查询里可以直接做算术;ORDER BY可以引用别名。参数上要注意,Access 的 WHERE 子句里不能用 SELECT 里定义的别名,必须重复写表达式,这是它和很多数据库的差异。

聚合查询则是把明细压成汇总:

-- 按产品统计销售数量和总金额 SELECT 产品ID, SUM(数量) AS 总数量, SUM(数量 * 单价) AS 总金额 FROM 订单明细 GROUP BY 产品ID HAVING SUM(数量 * 单价) > 10000;

这里HAVING是对聚合结果过滤,WHERE是对明细行过滤,两者不能混。很多人写错就是把聚合条件塞进 WHERE,报「聚合函数不能出现在 WHERE 子句」的错。

2.4 交叉表查询:行转列在 Access 里的实现

交叉表查询是 Access 做报表的利器,本质是行转列。比如按月份和产品做销售矩阵,行是产品,列是月份,值是金额。在查询设计视图里选「交叉表查询」,指定行标题、列标题、值三个角色即可,SQL 视图里对应TRANSFORM ... PIVOT:

-- 按产品和月份生成销售交叉表 TRANSFORM SUM(数量 * 单价) AS 销售额 SELECT 产品ID FROM 订单明细 GROUP BY 产品ID PIVOT Format(下单日期, 'yyyy-mm');

TRANSFORM指定值字段和聚合方式,PIVOT指定列标题来源。注意PIVOT的列是动态的,月份多了列就多,导出到 Excel 时列数会变,做固定模板报表时要留意这一点。另外Format函数返回的是文本,排序会按字符串排(「2024-10」排在「2024-2」后面),需要的话在 PIVOT 里用Month()取数字再拼。

3. 数据转换实战:脏数据清洗的六个固定动作

3.1 查找和删除重复记录

重复记录是分析前必清的东西。Access 里有两个层次:一是用「查找重复项查询向导」快速定位,二是用聚合查询按业务主键分组、COUNT(*) > 1筛出重复组。删除时要小心,不能直接DELETE全删,得保留一条。常见做法是建一个生成表查询,把每组里MIN(自动编号)的那条留下来:

-- 找出每个订单号下重复的明细,保留最小 ID 的一条 SELECT MIN(ID) AS 保留ID, 订单号, COUNT(*) AS 重复次数 FROM 订单明细 GROUP BY 订单号 HAVING COUNT(*) > 1;

拿到「保留ID」列表后,再写删除查询DELETE FROM 订单明细 WHERE ID NOT IN (SELECT 保留ID FROM ...)。注意 Access 的删除查询不支持直接对子查询做NOT IN时引用同表,稳妥做法是先把保留ID生成到临时表,再基于临时表删。

3.2 填充空白字段与字段连接

空白字段分两种:NULL 和空字符串。Access 里IsNull()判断 NULL,Len(字段)=0判断空串,两者要分开处理。填充常用Nz()函数:

-- 把备注为 NULL 的填成「未填写」,同时拼接客户名和订单号 SELECT Nz(备注, '未填写') AS 备注2, 客户名 & '-' & 订单号 AS 业务编号 FROM 订单主表;

Nz(字段, 替代值)是 Access 特有函数,等价于COALESCE;&是字符串连接符,遇到 NULL 时&会把 NULL 当空串处理,而+会让整个表达式变 NULL,这是很多人踩过的坑。字段连接常用于生成业务唯一键,比如「客户名-订单号」拼起来做匹配键。

3.3 文本清洗:大小写、空格、查找替换

文本转换是书里花篇幅最多的部分,因为从业务系统导出的数据经常带首尾空格、大小写不一致、夹杂特殊字符。常用函数组合:

-- 去首尾空格、统一大写、替换掉全角括号 SELECT UCase(Trim(客户名)) AS 规范客户名, Replace(Replace(地址, '(', '('), ')', ')') AS 规范地址 FROM 客户表;

Trim()去首尾空格,UCase()/LCase()转大小写,Replace()做查找替换。注意Trim()只去空格不去制表符和换行,从网页或 PDF 复制来的数据常带Chr(9)、Chr(13),需要嵌套Replace(字段, Chr(13), '')处理。批量清洗建议写成更新查询,把结果写回原表,但更新前一定先备份,更新查询没有撤销。

3.4 操作查询的四种类型与使用顺序

操作查询包括生成表查询、删除查询、追加查询、更新查询。书里给的顺序建议是:先用生成表查询把清洗结果落到临时表,验证无误后再用追加查询并入主表,删除和更新放在最后且必须限定条件。一个典型的数据流转:

-- 第一步:生成清洗后的临时表 SELECT 订单号, UCase(Trim(客户名)) AS 客户名, 数量, 单价 INTO 订单明细_清洗 FROM 订单明细 WHERE 数量 > 0 AND 单价 IS NOT NULL; -- 第二步:把临时表追加回主表(主表需先清空或按订单号去重) INSERT INTO 订单明细_正式 (订单号, 客户名, 数量, 单价) SELECT 订单号, 客户名, 数量, 单价 FROM 订单明细_清洗;

INTO是生成表查询的写法,目标表不存在时自动创建;INSERT INTO ... SELECT是追加查询。参数上要注意字段顺序必须一一对应,类型要兼容,文本追加到数字字段会报类型转换错误。操作查询执行时 Access 会弹确认框,批量跑之前建议在「选项」里关掉确认,但关掉后就没有后悔药了,所以备份是硬性要求。

4. 避坑与排查:五个真实踩过的坑

4.1 导入后数字变文本,聚合全为 0

现象:从 Excel 导入的金额列,SUM结果是 0,或者排序按字符串排(「9」排在「10」后面)。原因:源列里混了千分位、货币符号或空格,Access 判定为文本型。解决:导入前在 Excel 里用「分列」或VALUE()转成纯数字,导入后在 Access 里用CDbl(字段)或CLng(字段)做一次转换查询再入正式表。

4.2 日期条件查不到数据

现象:WHERE 下单日期 >= #2024-01-01#返回空。原因:字段实际是文本型,或者日期格式受系统区域设置影响,#2024-01-01#被解析成#2024-01-01 00:00:00#之外的格式。解决:先用SELECT DISTINCT 下单日期 FROM 表看实际存储值,确认类型;文本日期用CDate()转换后再比较;跨区域环境统一用#yyyy-mm-dd#格式。

4.3 连接查询结果行数暴增

现象:两张表按订单号连接,结果行数远大于明细表。原因:连接字段一方有重复值(比如订单主表里订单号不唯一),一对多变成多对多。解决:连接前先对主表按连接键做GROUP BY去重,或者确认主表连接键上有唯一索引;在关系窗口里勾选参照完整性,从源头约束。

4.4 更新查询改错数据无法回滚

现象:更新查询条件写漏了一个AND,整表被覆盖。原因:Access 的更新查询执行即生效,没有事务回滚入口(除非用 VBA 包事务)。解决:执行前先复制一份表做备份;把更新查询的WHERE条件先用选择查询验证一遍,确认命中行数和预期一致再改成更新;复杂更新拆成多步小查询。

4.5 交叉表列名动态导致导出错位

现象:每月跑同一个交叉表,导到 Excel 后列顺序变了,模板对不上。原因:PIVOT的列按数据动态生成,某月没数据就少一列。解决:在 PIVOT 前用固定维度表左连接补齐所有月份,或者导出后在 Excel 侧按列名匹配而不是按位置取数;固定报表场景干脆不用交叉表,改用多个聚合查询拼结果。

5. 进阶:把查询层固化成可复用的分析流水线

书里最后落到的是「数据与呈现分离」这个理念,落到实操上就是:把所有清洗和聚合逻辑固化成命名查询,Excel 只负责连进来取结果出图。具体做法是建一组查询,按依赖顺序命名,比如qry_01_清洗明细、qry_02_聚合月度、qry_03_交叉表,后面的查询引用前面的查询,形成一条流水线。这样源数据更新后,只需要重新打开依赖链末端的查询,整条链自动重算,不用手工重复每一步。

验证流水线是否可靠,我一般用三个检查点:一是行数守恒,清洗前后明细行数差异要能解释(删了多少重复、过滤了多少无效);二是金额对账,聚合查询的总金额和源表SUM一致;三是抽样比对,随机抽十条记录手工核对清洗结果。这三个检查点写成固定查询,每次数据更新后跑一遍,比肉眼扫一遍靠谱得多。

一个实用技巧是把参数查询和流水线结合,让同一套查询支持不同时间范围:

-- 参数查询:运行时弹出输入框,指定起止日期 SELECT 产品ID, SUM(数量 * 单价) AS 销售额 FROM 订单明细 WHERE 下单日期 BETWEEN [请输入开始日期:] AND [请输入结束日期:] GROUP BY 产品ID;

方括号里的文字就是提示语,运行时弹出输入框,输入的值按日期类型参与比较。参数查询的好处是同一份查询可以反复用,不用每次改 SQL;坏处是不能被其他查询直接引用(参数需要外部传入),所以流水线里参数查询一般放在最末端做展示层,中间层用固定条件的查询。

从那以后我每次把 Excel 数据往 Access 里搬,都强制先走一遍「类型检查 → 去重 → 清洗 → 生成临时表 → 对账」这五步,哪怕数据看起来再干净也不跳过,因为翻车基本都翻在「看起来没问题」的那一列上。希望这套流程帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进