使用 DuckDB 执行 SQL 查询
使用 SQL 查询电子表格数据及外部数据库
概述
ModelMonkey 内置了由 DuckDB 驱动的 SQL 引擎,可让您直接对电子表格数据运行 SQL 查询。您还可以查询外部数据库(PostgreSQL、BigQuery),甚至跨多个数据源进行联合查询。
当您需要对数据转换进行精确控制、执行复杂的聚合运算,或需要以自然语言难以清晰表达的方式合并来自不同来源的数据时,此功能非常实用。
Tip
您无需自己编写 SQL。只需用自然语言描述您的需求,ModelMonkey 会自动为您生成并执行相应的 SQL 查询。
SQL 查询的适用场景
当您的请求涉及以下情况时,ModelMonkey 会自动使用 SQL 查询:
复杂聚合
对大量数据行进行分组、求和、求平均值、计数或其他统计运算。
筛选与排序
根据多个条件查找特定记录,或按不同标准对大型数据集进行排序。
数据连接
将电子表格数据与外部数据库合并,或将多个工作表联合在一起。
数据转换
对数据进行重新格式化、计算新列,或以需要逐行处理的方式重构数据。
如果您希望针对某项操作使用 SQL 的精确性,也可以明确要求 ModelMonkey "使用 SQL" 或 "运行 SQL 查询"。
查询电子表格数据
您的电子表格数据可通过 sheet_range() 函数访问。该函数接受 A1 表示法引用,并将数据作为可查询的表返回。
重要要求
- 所选范围的第一行必须包含列标题
- 列名称从标题行中提取
- 空标题将生成类似 "column_1"、"column_2" 等的列名
支持的范围格式
- 完整工作表:
sheet_range('Sheet1!A:Z') - 特定范围:
sheet_range('Sales!A1:D100') - 包含特殊字符的命名范围会自动转义
-- Query all data from a sheet
SELECT * FROM sheet_range('Sheet1!A1:D100')
-- Filter and aggregate
SELECT category, SUM(amount) as total
FROM sheet_range('Sales!A1:E500')
WHERE date >= '2024-01-01'
GROUP BY category
-- Sort by multiple columns
SELECT * FROM sheet_range('Customers!A:F')
ORDER BY region ASC, revenue DESC电子表格查询示例
查询外部数据库
如果您已配置外部数据连接,可以使用连接名称对其进行查询:
PostgreSQL
以 connection_name.schema.table 的形式引用表。默认 schema 通常为 "public"。
BigQuery
以 connection_name.dataset.table 的形式引用表。
外部数据库查询与标准 SQL 完全一致,您可以使用 DuckDB 支持的所有功能,包括连接查询、子查询、窗口函数和 CTE。
Tip
请先在"外部数据连接"面板中配置外部连接,然后再进行查询。
-- Query a PostgreSQL table
SELECT * FROM my_postgres.public.customers
WHERE country = 'USA'
-- Query a BigQuery table
SELECT event_date, COUNT(*) as events
FROM my_bigquery.analytics.page_views
GROUP BY event_date
-- Join PostgreSQL with BigQuery
SELECT p.name, b.total_events
FROM my_postgres.public.products p
JOIN my_bigquery.analytics.product_stats b
ON p.id = b.product_id外部数据库查询示例
连接电子表格与数据库数据
跨不同数据源进行联合查询是最强大的功能之一。您可以在单个查询中将电子表格数据与外部数据库合并使用。
常见应用场景
- 用数据库中的客户数据丰富电子表格记录
- 将本地追踪数据与数据仓库进行对比
- 根据外部参考表验证电子表格条目
- 将工作表中的销售数据与数据库中的产品目录合并
-- Join spreadsheet orders with database customers
SELECT
s.order_id,
s.order_date,
s.amount,
c.customer_name,
c.email,
c.tier
FROM sheet_range('Orders!A1:D500') s
JOIN my_postgres.public.customers c
ON s.customer_id = c.id
WHERE s.amount > 1000
-- Cross-database aggregation
SELECT
c.country,
COUNT(*) as order_count,
SUM(s.amount) as total_sales
FROM sheet_range('Sales!A1:C1000') s
JOIN my_postgres.public.customers c
ON s.customer_id = c.id
GROUP BY c.country
ORDER BY total_sales DESC跨数据源连接查询示例
查询输出选项
查询结果可通过两种方式呈现:
内联结果(默认)
结果直接返回至 ModelMonkey 进行分析和推理。这适用于探索性查询,即您希望先了解数据再决定如何处理的场景。
- 默认最多返回 20 行(可配置至最多 100 行)
- 包含列类型及元数据
- 适合快速数据探索
输出至工作表
结果直接写入电子表格中的新工作表。当您希望保留查询结果以供后续使用时,此方式非常实用。
- 以您指定的名称创建新工作表
- 包含所有行(无行数限制)
- 自动添加标题行
- 非常适合创建报表或暂存数据
Tip
向 ModelMonkey 请求"将结果保存到新工作表"或"将输出写入名为 Results 的工作表",即可使用工作表输出模式。
数据类型处理
ModelMonkey 会自动从您的电子表格数据中推断列类型:
支持的类型
- 数字:整数和小数将被检测并作为数值类型处理
- 布尔值:TRUE/FALSE 值将被识别为布尔类型
- 文本:其他所有内容均作为文本(VARCHAR)处理
- 日期:单元格中的日期值通常作为文本处理;请使用 SQL 日期函数对其进行解析
类型推断过程
ModelMonkey 会对数据的前几行进行采样,以确定每列的适当类型。如果某列包含混合类型,则默认为文本类型以避免数据丢失。
-- Parse date strings in queries
SELECT
order_id,
strptime(order_date, '%Y-%m-%d') as parsed_date,
amount
FROM sheet_range('Orders!A1:C100')
WHERE strptime(order_date, '%Y-%m-%d') >= DATE '2024-01-01'
-- Cast numeric strings
SELECT
product_name,
CAST(price AS DOUBLE) as numeric_price
FROM sheet_range('Products!A1:B50')数据类型处理示例
性能注意事项
查询执行
- 查询超时时间为 30 秒
- 出于安全考虑,最大结果集为 16,384 行
- 大型电子表格范围将被加载到内存中进行查询
最佳实践
- 指定精确范围,而非整列(例如使用
A1:D500而非A:D) - 使用 WHERE 子句提前过滤数据,减少处理量
- 对于非常大的数据集,考虑使用工作表输出以避免内存问题
- 为大型外部数据库表建立索引以加速连接查询
缓存
查询结果不会在请求之间缓存。每次查询都会重新读取当前电子表格数据,确保您始终获取最新值。
Warning
非常大的范围(数万行)可能会降低查询执行速度。对于大规模分析,请考虑过滤数据或使用外部数据库。
支持的 SQL 功能
ModelMonkey 通过 DuckDB 支持多种 SQL 功能:
标准操作
- SELECT、FROM、WHERE、ORDER BY、LIMIT
- GROUP BY 与聚合函数(SUM、COUNT、AVG、MIN、MAX 等)
- DISTINCT 和 HAVING 子句
- UNION、INTERSECT、EXCEPT
连接查询
- INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL OUTER JOIN
- 交叉连接和自连接
- 多表连接
高级功能
- 子查询和 CTE(WITH 子句)
- 窗口函数(ROW_NUMBER、RANK、LAG、LEAD 等)
- CASE 表达式
- 字符串函数、日期函数、数学函数
不支持的功能
- INSERT、UPDATE、DELETE(查询为只读)
- CREATE TABLE、ALTER TABLE(不支持 schema 修改)
- 存储过程或用户自定义函数
查询示例
以下是一些您可能会用到的实用 SQL 查询示例:
-- Monthly sales summary
SELECT
strftime(strptime(date, '%Y-%m-%d'), '%Y-%m') as month,
COUNT(*) as num_orders,
SUM(amount) as total_revenue,
AVG(amount) as avg_order_value
FROM sheet_range('Orders!A1:D1000')
GROUP BY month
ORDER BY month DESC
-- Find duplicate entries
SELECT email, COUNT(*) as count
FROM sheet_range('Contacts!A1:E500')
GROUP BY email
HAVING COUNT(*) > 1
-- Top customers by spending
SELECT
customer_id,
SUM(amount) as total_spent,
COUNT(*) as num_orders
FROM sheet_range('Orders!A1:D1000')
GROUP BY customer_id
ORDER BY total_spent DESC
LIMIT 10
-- Running total with window function
SELECT
date,
amount,
SUM(amount) OVER (ORDER BY date) as running_total
FROM sheet_range('Transactions!A1:C100')实用 SQL 查询示例
故障排除
"列未找到"错误
- 检查标题行是否包含预期的列名
- 列名区分大小写
- 列名中的空格可以使用,但在复杂查询中可能需要加引号
"范围无效"错误
- 确认工作表名称拼写正确
- 确保该范围存在且包含数据
- 检查工作表名称中是否有需要转义的特殊字符
"查询超时"错误
- 简化查询或缩小数据范围
- 添加 WHERE 子句以提前过滤数据
- 对于大型结果集,考虑使用工作表输出
"连接未找到"错误
- 确认外部连接名称正确
- 检查"外部数据连接"面板中该连接是否处于活动状态
- 确认您有权访问该外部数据库
空结果或意外结果
- 检查数据类型是否与 WHERE 条件匹配
- 确认日期格式与电子表格中的格式一致
- 检查文本数据中是否存在前导/尾随空格