仅靠公式,Google Sheets 能走出相当远——直到有人要求跨三张工作表做多表 JOIN,或按业务单元和季度分区的窗口函数。到了那一步,SUMIFS 就明显力不从心了。
但更关键的问题是:你需要会写 SQL 吗?不需要。 这套集成的核心价值在于,你用自然语言描述所需分析——"把损益表按产品代码关联产品主数据,按 BU 和季度汇总毛利率"——AI Agent 生成并执行 SQL,结果直接写入指定的工作表区域。SQL 引擎在后台运行,你只需要提需求。
这是这套技术真正的卖点。下面是它的运作方式,以及在接入之前值得了解的边界条件。
DuckDB 为 Google Sheets 带来了什么
Google Sheets 内置的 QUERY() 函数使用一种受限的 SQL 方言。基本的 SELECT 和 WHERE 没有问题,但面对跨多个数据范围的操作、JOIN 之后的聚合,或窗口函数,便力不从心。
DuckDB 是一个完整的 OLAP 引擎,支持标准 SQL——包括 CTE、窗口函数,以及用于过滤窗口函数结果的 QUALIFY 子句(参见 DuckDB 官方 SQL 文档)。两者的核心差异如下:
| 功能 | QUERY() | DuckDB |
|---|---|---|
| 基础 SELECT / WHERE | ✓ | ✓ |
| 多表 JOIN | ✗ | ✓ |
| 窗口函数(滚动均值、累计总量) | ✗ | ✓ |
| CTE(公共表表达式) | ✗ | ✓ |
| HAVING 过滤聚合结果 | 受限 | ✓ |
| 跨工作表范围查询 | ✗ | ✓ |
架构层面只有一点需要记住:QUERY() 在 Sheets 公式引擎内部执行,受限于该引擎暴露的能力;DuckDB 作为独立数据库运行,将工作表数据作为表格输入读取。你的电子表格从执行环境变成了数据源。
一位财务分析师在构建跨产品线和大区的贡献毛利分析时——那种目前往往存在于十几张工作表、塞满 VLOOKUP 链的工作簿中的季报分析——可以将其压缩为一条针对原始数据范围的 SQL 查询。HAVING 直接过滤聚合结果,不需要嵌套四层 SUMIFS 再对不上数。
集成是如何运作的
让 DuckDB 对 Google Sheets 数据进行操作,有两种基本思路,《如何将 DuckDB 连接到 Google Sheets》 中有更详细的介绍。
方式一:导出再查询。 将数据导出为 CSV 或 Parquet,在本地运行 DuckDB,再将结果导回。可行,但数据在导出的那一刻就已过时,每次数据更新都要重新手动操作。
方式二:原生嵌入。 让查询引擎实时访问工作表数据范围。这正是 ModelMonkey 的实现方式:一个名为 sheet_range() 的表函数被注册为 DuckDB UDF,让 SQL 查询可以直接以 A1 表示法引用电子表格数据。
SELECT
category,
SUM(revenue) AS total_revenue,
AVG(margin_pct) AS avg_margin
FROM sheet_range('P&L!B2:E500')
GROUP BY category
ORDER BY total_revenue DESC
查询针对实时数据运行,无需导出步骤。列类型根据数据自动推断——数字以 DOUBLE 传入,布尔值为 BOOLEAN,混合内容默认为 VARCHAR。截至 2026 年 4 月,类型推断对大多数财务数据处理良好,但当某列中标题文本与数值数据混杂时,偶尔需要用 TRY_CAST() 做显式类型转换。
真实工作流:按 BU 和季度汇总 EBITDA 贡献度
设想一位财务分析师需要向投资人汇报各业务单元的季度 EBITDA 贡献度:损益明细在一张工作表,BU 映射关系在另一张,费用科目分类在第三张。用 VLOOKUP 链和 SUMIFS 搭建,要花半天,而且每次 BU 架构调整就得返工。
用自然语言向 Agent 描述需求后,执行的查询大致如下:
SELECT
m.bu_name AS 业务单元,
pl.quarter AS 季度,
ROUND(SUM(pl.revenue) / 1e4, 2) AS 营收_万元,
ROUND(SUM(pl.gross_profit) / 1e4, 2) AS 毛利_万元,
ROUND(100.0 * SUM(pl.gross_profit) / NULLIF(SUM(pl.revenue), 0), 1) AS 毛利率_pct,
ROUND((SUM(pl.gross_profit) - SUM(pl.opex)) / 1e4, 2) AS EBITDA贡献_万元
FROM sheet_range('PL明细!B2:G2000') pl
JOIN sheet_range('BU映射!A2:C200') m ON pl.product_code = m.product_code
GROUP BY m.bu_name, pl.quarter
HAVING SUM(pl.revenue) > 0
ORDER BY m.bu_name, pl.quarter
一条查询,三张工作表,结果直接输出到汇报用的汇总工作表。没有中间列,没有 VLOOKUP 链,没有需要手动刷新的数据透视表。
数据溯源同样清晰:系统追踪每次查询访问了哪些数据范围,Agent 可以解释推理过程——"我查询了 PL明细!B2:G2000 和 BU映射!A2:C200,通过 product_code 进行了关联。"下周数据更新、重新跑查询时,你能清楚知道数字来自哪里——比追溯嵌套函数层级反而更透明。
需要了解的实际限制
数据量上限。 Google Sheets 的硬性上限是 1000 万个单元格(Google Docs 编辑器帮助文档)。DuckDB 本身能处理的数据量远不止于此,但在 Sheets 集成场景下,上限由 Sheets 决定。对于完全存储在工作表中的业务数据,这个量级通常绰绰有余。
输出大小。 将 5 万行原始数据内联返回到电子表格中既缓慢又没有意义——你要的是聚合结果。合理的集成方案将内联结果限制在约 200 行;更大的输出需要指定写入目标工作表区域,而不是直接展示在对话界面里。
查询延迟。 DuckDB 实例在内存中运行,本身很快。瓶颈通常在于从 Sheets API 获取数据范围,往返延迟与范围大小成正比。针对大型数据范围的复杂 JOIN 可能需要数秒时间,提前做好预期管理。
常见问题
我需要会写 SQL 才能使用吗? 不需要。你用自然语言描述分析需求,Agent 生成并执行 SQL,结果写入工作表。如果你本身会写 SQL,也可以直接提交查询语句——两种方式均支持。
和直接导出 CSV 相比,有什么本质区别? 导出方式下,数据在导出的那一刻就已过时,每次数据更新都需要重新手动操作。原生嵌入方式下,查询直接读取工作表当前数据,结果始终反映最新状态——对于每日更新的运营类看板或滚动预测尤其关键。
工作表数据更新后,结果会自动刷新吗? 不是自动刷新,而是按需重跑。重新执行查询时,读取的是工作表当前数据。如果需要定时刷新,可以配置定期触发查询的规则。
结果集超过 200 行怎么办?
在查询时指定 output:"sheet" 参数,结果将直接写入指定的命名工作表区域,而不是显示在对话界面里。完整结果集始终可以访问,同时保持交互界面简洁。
小结
Google Sheets DuckDB 集成带来了真正的 SQL 能力——JOIN、窗口函数、聚合——直接作用于实时工作表数据,无需任何导出操作。核心价值在于:你描述分析需求,AI 生成并执行 SQL,结果写入工作表,数据溯源清晰可追溯。实际边界是 Google Sheets 的 1000 万单元格上限、约 200 行的内联结果限制,以及大数据范围的 API 获取延迟。
查看 ModelMonkey 方案——同时支持 Google Sheets 和 Excel。