前面九节一直在数据库里工作。现在我们要解决一个很实际的问题:SQL 算出的结果怎样进入 Excel,并且在 SQL 重新计算后,不靠复制粘贴就能更新。
这里的“联动”有一个明确标准。SQL 负责生成口径稳定的结果文件,Excel 用 Power Query 记住文件路径、编码和字段结构。SQL 再次导出后,在 Excel 中单击“全部刷新”,表格和基于它的图表一起更新。只把 CSV 打开一次,不算联动,因为下次数据变化时还得重新复制。
这一节会完整走一遍这条链路,并专门处理中文乱码、日期识别和总额对账。
Excel 能处理明细,不代表我们应该把所有明细都塞进去。本项目的销售视图有 1271 行,规模并不大,但看板真正需要的是月度、品类、城市和留存这几张结果表。
我建议先在 SQL 中完成连接、过滤和聚合,再把结果交给 Excel,理由有三点:
这并不表示 Excel 不能写公式。Excel 公式在后面仍会用于复核客单价、毛利率、环比和移动平均。区别在于,复杂的业务口径只定义一次,Excel 的公式是可见的检查层和展示层。
导出前先把每张结果表的用途写清楚:
输出契约的作用很直接:如果 Excel 刷新后只有 17 个月,我们先查导出文件,而不是先怀疑图表。
在 SQLite 命令行中执行下面的脚本:
.headers on
.mode csv
.once monthly.csv
WITH monthly AS (
SELECT
order_month,
COUNT(DISTINCT order_id) AS orders,
COUNT(DISTINCT customer_id) AS customers,
ROUND(SUM(revenue), 2) AS revenue,
ROUND(SUM(gross_profit), 2) AS gross_profit
FROM v_sales_detail
GROUP BY order_month
)
SELECT
order_month,
orders,
customers,
revenue,
gross_profit
FROM monthly
ORDER BY order_month;这次只导出五列。客单价、毛利率、环比和三个月移动平均暂时不写进 CSV,下一节会在 Excel 中亲手计算一遍。这样我们既保留 SQL 的原始汇总结果,也能验证 Excel 公式是否与 SQL 口径一致。
.once 只把紧接着的一条查询写入文件。它比永久重定向更安全:查询结束后,后续 SQL 结果会重新显示在终端,不会悄悄追加到 CSV。
导出后先在 SQLite 中做对账,不要等到 Excel 才发现问题:
SELECT
COUNT(DISTINCT order_month) AS months,
ROUND(SUM(revenue), 2) AS revenue
FROM v_sales_detail;结果应为 18 个月、销售额 229909.45。这个数字是后面所有刷新测试的基准。
CSV 中的销售额应写成 13278.95,不要写成 13,278.95 元。后者既包含额外逗号,又带单位,Excel 很容易把它识别为文本。
数值的展示格式交给 Excel:原始值保持纯数字,工作簿再决定是否显示千位分隔符、货币符号或小数位。这样公式、排序和图表都能继续使用这些单元格。
CSV 文件本身没有强制记录编码。某些 Excel 环境会把没有标记的 UTF-8 文件按其他编码解释,于是“品类”可能变成“鍝佺被”一类乱码。
我们采用两层保护:文件使用 UTF-8,并在最前面加 UTF-8 BOM;导入时仍明确选择 Unicode (UTF-8)。BOM 是三个字节的编码提示,不会成为数据表中的一列。
如果导出工具没有自动写 BOM,可以在项目目录执行:
(printf '\xEF\xBB\xBF'; cat monthly.csv) > monthly_utf8.csv接着不要双击后直接点“完成”。在文本导入向导中按顺序检查:
Unicode (UTF-8)。
乱码不能靠在 Excel 里手工改标题解决。标题改对了,品类、城市和客户分群仍然是错的,后续筛选会继续出问题。正确做法是回到编码和导入设置,从源头重新载入。
直接用“文件 > 打开”可以检查 CSV,但它不会保存一个可刷新的数据连接。要让 SQL 与 Excel 联动,我们使用 Power Query。
在已经保存为 .xlsx 的工作簿中完成下面的操作:
Text/CSV,选择这个数据源。monthly_utf8.csv。65001: Unicode (UTF-8)。Comma。预览页不是形式上的确认。它同时验证路径、编码、分隔符和字段类型:

加载完成后,Excel 会新建一张查询表,并保存数据源路径。日期列应显示为日期,订单数和客户数应是整数,销售额与毛利额应是数值。

Power Query 可能自动生成 monthly_utf8 或 monthly_utf8 (2)。把查询命名为 q_monthly,工作表命名为“月度数据”。前缀 q_ 表示这是一个查询,不是手工录入表。
名字看起来是小事,等工作簿里有月度、品类、城市和留存四个数据源时,它能避免你把图表接到错误的表上。
刷新链路是:
SQLite 查询
-> 覆盖 monthly_utf8.csv
-> Excel Power Query 重新读取文件
-> 查询表更新
-> 引用查询表的公式和图表重算Power Query 不会替你重新执行 SQLite。先运行 SQL 导出脚本,再在 Excel 中选择“数据 > 全部刷新”。如果只刷新 Excel 而没有重新导出,读到的仍是旧 CSV。
建立连接后不要凭感觉说“已经联动”。我们用一个可回滚的测试验证。
我们实际做了两轮刷新:先让源文件的末月销售额暂时变为 11999.01,Excel 刷新后同步得到这个值;随后重新运行 SQL 恢复 11998.01,再次刷新,工作簿也恢复正式结果。这证明 Excel 读取的是数据源,而不是一份静态复制。
真实项目不需要手改业务数字。这里的临时改动只用于验证连接,测试后必须重新运行正式 SQL 并再次对账。
月度表应有 1 行表头和 18 行数据,范围是 A1:E19。A 列是月份,B 到 E 列是数值。
选中销售额列后,状态栏应能显示求和。若没有求和,或 =SUM(D2:D19) 返回 0,说明销售额可能是文本。
文本数字常见原因包括:小数点被当作字符、金额中混入单位、编码导致不可见字符。不要直接在每个单元格里改,应该修复导出规则后刷新。
在空白单元格输入:
=SUM(D2:D19)结果必须是 229909.45。然后再检查毛利额:
=SUM(E2:E19)结果应是 113296.45。
月份应按 2024-01 到 2025-06 排序。如果出现 2025-01 排在 2024-12 前面,先确认 A 列是真日期还是文本。
Power Query 把 2024-01 识别成 2024/1/1 是正常的。它代表这个月的第一天,后续可以把显示格式改成 yyyy-mm,不需要把值改回文本。

Power Query 记住的是路径。文件被移动或改名后,查询仍会找旧位置。打开“查询与连接”,进入数据源设置,重新选择文件。正式交付时,CSV 与工作簿最好放在一个固定目录中,并在交付说明中写明刷新顺序。
先检查查询表本身是否变化。表变了但图没变,通常是图表仍引用一段固定区域;表没变,则问题在导出路径或查询刷新。
这不是乱码。Excel 把月份识别成日期,并按当前区域格式显示。把单元格格式改成 yyyy-mm 即可,底层日期值不需要改变。
Command + T 后 Excel 无响应先保存工作簿,再通过“插入 > 表格”创建表。如果快捷键触发异常,退出未完成的编辑状态后再操作。表对象很有用,但不是联动的必要条件;Power Query 加载的结果本身已经是一张可刷新的表。
到这里,SQL 与 Excel 已经连接起来。下一节会在这张可刷新月度表上写复核公式,并完成月度趋势图、品类条形图和留存热力图。