Featured image of post 用 DuckDB 搭建自动化财报分析系统:月度环比 + 预算预警全解

用 DuckDB 搭建自动化财报分析系统:月度环比 + 预算预警全解

手把手教你用 DuckDB 搭建自动化财报分析系统:多数据源 CSV 聚合、LAG 窗口函数计算月度环比增长、预算执行率预警,一键导出 Excel,挂上 FastAPI 当 SaaS 卖。完整 Python 代码直接可用。

为什么选这个项目?

很多数据分析师接私单时,最耗时的就是每月帮客户跑财务数据、生成报表。手动操作容易出错,而且无法复用——换一个客户又要重写一遍。

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 里完成,不需要把数据拉到 Python
  • LAG() 窗口函数获取上一个月的值,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);
""")

变现路径总结

  1. 接单私活:在猪八戒、码市等平台发布"财务自动化报表"服务,标价 ¥5,000-15,000/单
  2. SaaS 订阅:把系统部署到云服务器,每月向客户收取 ¥500-2,000 的订阅费
  3. 模板出售:把代码封装成可配置的模板,在 Gumroad 或闲鱼上卖 ¥99-299/份
  4. 企业内训:给中小企业做 DuckDB 自动化报表培训,¥3,000-8,000/场
  5. 知识库产品:把你的实战经验整理成付费教程,挂在知识星球或小报童上

架构图

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

📺 Watch video tutorials → Olap Studio YouTube

Subscribe for more DuckDB & AI automation tutorials

使用 Hugo 构建
主题 StackJimmy 设计

⚠️ 本站为独立社区项目,与 DuckDB 基金会及 DuckDB 官方项目无任何从属、背书或赞助关系。

"DuckDB" 是 DuckDB 基金会的注册商标,本站仅以事实描述方式使用该名称。

本站内容仅供教育与社区推广用途,不构成任何商业服务。