为什么选这个项目?
很多数据分析师接私单时,最耗时的就是每月帮客户跑财务数据、生成报表。手动操作容易出错,而且无法复用——换一个客户又要重写一遍。
用 DuckDB,你可以在 10 分钟内 完成一套可复用的自动化分析系统,直接作为你接单的"标配交付物",甚至做成 SaaS 向更多客户收费。这个项目的核心价值在于:它把「重复劳动」变成了「一次性开发,永久复用」。
第一步:搭建多数据源环境
我们假设一家公司的财务数据散落在多个 CSV 文件中。DuckDB 的 read_csv_auto 能自动推断 schema,无需手动定义列类型:
import duckdb
from duckdb import connect
# 连接内存数据库,所有查询在内存完成,速度极快
con = connect(":memory:")
# 模拟三张表:收入明细、成本明细、部门预算
con.execute("""
CREATE TABLE revenue AS
SELECT date, product, amount, region
FROM read_csv_auto('revenue_2024.csv')
WHERE date >= '2024-01-01';
CREATE TABLE costs AS
SELECT date, category, amount, dept
FROM read_csv_auto('costs_2024.csv')
WHERE date >= '2024-01-01';
CREATE TABLE budget AS
SELECT dept, year, quarter, allocated
FROM read_csv_auto('budget_2024.csv');
""")
💡 真实场景中数据通常在 PostgreSQL 或 MySQL 里,用
postgres_scan/mysql_scan直接连接,无需 ETL 搬运:con.execute(""" CREATE VIEW financial_data AS SELECT * FROM postgres_scan( 'dbname=finance host=localhost user=xxx password=xxx' ) """)
第二步:核心分析查询
2.1 月度收入趋势(带环比)
环比(MoM, Month-over-Month)是老板最关心的指标——比上月增长了多少?
monthly_revenue = con.execute("""
SELECT
date_trunc('month', date) AS month,
product,
SUM(amount) AS total_revenue,
LAG(SUM(amount)) OVER (
PARTITION BY product
ORDER BY date_trunc('month', date)
) AS prev_month_revenue,
ROUND(
100.0 * (SUM(amount) - LAG(SUM(amount)) OVER (
PARTITION BY product ORDER BY date_trunc('month', date)
)) / NULLIF(LAG(SUM(amount)) OVER (
PARTITION BY product ORDER BY date_trunc('month', date)
), 0),
2
) AS mom_pct
FROM revenue
GROUP BY month, product
ORDER BY month, product
""").df()
关键点:
date_trunc('month', date)是 DuckDB 的核心函数,比 pandas 的dt.to_period快 10 倍以上,且直接在 SQL 里完成,不需要把数据拉到 PythonLAG()窗口函数获取上一个月的值,PARTITION BY product确保每个产品独立计算环比NULLIF(..., 0)防止除以零的报错
2.2 部门预算执行率(预警逻辑)
budget_actual = con.execute("""
SELECT
b.dept,
b.year,
b.quarter,
b.allocated AS budget,
COALESCE(c.spent, 0) AS actual_spent,
ROUND(
100.0 * COALESCE(c.spent, 0) / b.allocated, 1
) AS spend_pct,
CASE
WHEN COALESCE(c.spent, 0) / b.allocated > 0.9 THEN '🔴 严重超支'
WHEN COALESCE(c.spent, 0) / b.allocated > 0.8 THEN '🟡 接近上限'
ELSE '🟢 正常'
END AS status
FROM budget b
LEFT JOIN (
SELECT dept, year, quarter, SUM(amount) AS spent
FROM costs
GROUP BY dept, year, quarter
) c USING (dept, year, quarter)
ORDER BY spend_pct DESC
""").df()
这个查询直接产出老板最想看的「预算执行预警表」,零 Python 循环,全靠 SQL 搞定。CASE WHEN 的三段式预警逻辑可以直接复用。
第三步:导出带格式的报告
3.1 导出为 Excel(带格式)
import pandas as pd
from openpyxl import load_workbook
from openpyxl.styles import Font, PatternFill, Alignment
# 导出两张表
monthly_revenue.to_excel('monthly_report.xlsx', sheet_name='收入趋势', index=False)
budget_actual.to_excel('monthly_report.xlsx', sheet_name='预算执行', index=False)
# 格式化表头
wb = load_workbook('monthly_report.xlsx')
for sheet_name in ['收入趋势', '预算执行']:
ws = wb[sheet_name]
ws.freeze_panes = 'A2' # 冻结首行
for cell in ws[1]:
cell.font = Font(bold=True, color='FFFFFF')
cell.fill = PatternFill('solid', fgColor='4472C4') # 深蓝背景
cell.alignment = Alignment(horizontal='center')
wb.save('monthly_report.xlsx')
3.2 一键打包为交付件
import shutil, zipfile
from datetime import datetime
filename = f"财务分析报告_{datetime.now().strftime('%Y%m%d')}.zip"
with zipfile.ZipFile(filename, 'w') as z:
z.write('monthly_report.xlsx')
z.writestr('README.txt', f'''
财务分析报告生成时间: {datetime.now()}
数据范围: 2024年Q1-Q3
生成工具: DuckDB + Python
备注: 如需重新生成,运行 gen_report.py 即可
''')
print(f"✅ 报告已生成: {filename}")
第四步:自动化 & API 化
4.1 挂到 cron 定时运行
# 每月 1 号凌晨 2 点自动生成财报
0 2 1 * * cd /path/to/project && python3 gen_report.py
4.2 做成 FastAPI 服务,客户随时查看
from fastapi import FastAPI
from fastapi.responses import FileResponse
import subprocess
from datetime import datetime
app = FastAPI()
@app.get("/report")
def get_report():
subprocess.run(["python3", "gen_report.py"], check=True)
return FileResponse(
f"财务分析报告_{datetime.now().strftime('%Y%m%d')}.zip",
media_type='application/zip'
)
@app.get("/revenue/trend")
def get_revenue_trend():
con = connect(":memory:")
con.execute("""
CREATE TABLE revenue AS
SELECT * FROM read_csv_auto('revenue_2024.csv');
""")
result = con.execute("""
SELECT date_trunc('month', date) AS month,
product, SUM(amount) AS total
FROM revenue GROUP BY month, product
ORDER BY month
""").df().to_dict('records')
return result
对比:传统方案 vs DuckDB 方案
| 维度 | 传统方案(Excel + Python 循环) | DuckDB 方案 |
|---|---|---|
| 月报表生成时间 | 2-4 小时 | 5-10 分钟 |
| 数据源扩展 | 每加一个文件要改代码 | read_csv_auto('*.csv') 自动合并 |
| 环比计算 | 嵌套 for 循环,容易出错 | 一条 SQL LAG() 窗口函数 |
| 预算预警 | Python 循环判断 | SQL CASE WHEN 一行搞定 |
| 可复用性 | 每个客户重写 | 换数据文件即可,逻辑不变 |
| 准确率 | 容易手抖填错行 | SQL 幂等执行,永远一致 |
📊 这个项目值多少钱?
| 场景 | 收费 |
|---|---|
| 帮一家中小企业每月生成财务分析报告 | ¥2,000-5,000/月 |
| 做成 SaaS,10 个客户 | ¥20,000-50,000/月 |
| 接一单定制开发(含系统设计) | ¥15,000-30,000/单 |
核心逻辑:你卖的不是"跑 SQL",而是"每月准时拿到老板满意的报表"。客户为结果付费,不是为工具付费。
进阶:生产环境优化
持久化存储(不需要每次都读 CSV)
# 首次运行:从 CSV 建表并持久化到 .duckdb 文件
con = duckdb.connect("finance.db")
con.execute("CREATE TABLE revenue AS SELECT * FROM read_csv_auto('revenue_2024.csv')")
con.execute("CREATE TABLE costs AS SELECT * FROM read_csv_auto('costs_2024.csv')")
con.execute("CREATE TABLE budget AS SELECT * FROM read_csv_auto('budget_2024.csv')")
con.close()
# 后续运行:直接打开数据库文件,秒级响应
con = duckdb.connect("finance.db")
# 查询逻辑完全一样,数据已在磁盘上
增量更新(只处理新增数据)
con.execute("""
-- 只导入本月新增的收入记录
INSERT INTO revenue
SELECT * FROM read_csv_auto('revenue_2024_08.csv')
WHERE date >= '2024-08-01'
AND date NOT IN (SELECT date FROM revenue);
""")
变现路径总结
- 接单私活:在猪八戒、码市等平台发布"财务自动化报表"服务,标价 ¥5,000-15,000/单
- SaaS 订阅:把系统部署到云服务器,每月向客户收取 ¥500-2,000 的订阅费
- 模板出售:把代码封装成可配置的模板,在 Gumroad 或闲鱼上卖 ¥99-299/份
- 企业内训:给中小企业做 DuckDB 自动化报表培训,¥3,000-8,000/场
- 知识库产品:把你的实战经验整理成付费教程,挂在知识星球或小报童上

学习更多 DuckDB 实战经验 → duckdblab.org