DuckDB 个人财务自动化:用 SQL 打造智能理财助手
场景引入:你的钱都去哪了?
很多人每个月发工资后都有一种迷茫——钱好像挣了不少,但月底一看余额,不知道怎么花光的。传统做法是用 Excel 记账,或者下载各种记账 App。但这些方案各有痛点:
- Excel 记账:手动输入繁琐,容易放弃;多个月的数据难以聚合分析
- 记账 App:数据存在别人服务器上,隐私担忧;想导出原始数据做自定义分析?门都没有
- 银行 App:只能看单家银行,多账户数据分散,无法统一分析
DuckDB 提供了一个全新的思路:把银行流水 CSV 下载到本地,用 SQL 快速分析,所有数据完全私有。整个过程不需要写一行 Python,一条 SQL 就能完成从数据导入到报表生成的全流程。

Step 1:导入银行流水数据
国内大部分银行都支持导出 CSV 格式的账单。以招商银行为例,导出格式通常包含:交易日期、交易时间、交易金额、余额、对方账户、交易摘要等字段。
import duckdb
from pathlib import Path
from datetime import datetime
# 连接内存数据库(无需安装,即开即用)
con = duckdb.connect(':memory:')
# 读取招商银行导出CSV
# 假设文件路径:~/Downloads/CMB_202609.csv
cmb_csv = Path.home() / 'Downloads' / 'CMB_202609.csv'
con.execute(f"""
CREATE TABLE cmb_transactions AS
SELECT * FROM read_csv_auto('{cmb_csv}',
header=true,
columns={{
'交易日期': 'VARCHAR',
'交易时间': 'VARCHAR',
'交易金额': 'DECIMAL(12,2)',
'余额': 'DECIMAL(12,2)',
'对方账户': 'VARCHAR',
'交易摘要': 'VARCHAR'
}}
)
""")
print(f"招商银行卡记录数: {con.execute('SELECT COUNT(*) FROM cmb_transactions').fetchone()[0]}")
💡 技巧:
read_csv_auto会自动推断列类型,但如果银行 CSV 格式不规范(比如日期格式混杂),可以通过columns参数手动指定。不同银行的导出格式略有差异,但 DuckDB 都能智能处理。
多银行数据合并
如果你有多个银行账户(招行、工行、支付宝、微信),可以分别导入后 UNION ALL 合并:
-- 读取工行的交易记录
CREATE TABLE icbc_transactions AS
SELECT * FROM read_csv_auto('~/Downloads/ICBC_202609.csv', header=true);
-- 读取支付宝账单
CREATE TABLE alipay_transactions AS
SELECT * FROM read_csv_auto('~/Downloads/ALIPAY_202609.csv', header=true);
-- 统一合并为一张总表
CREATE TABLE all_transactions AS
SELECT '招商银行' AS bank, * FROM cmb_transactions
UNION ALL
SELECT '工商银行' AS bank, * FROM icbc_transactions
UNION ALL
SELECT '支付宝' AS bank, * FROM alipay_transactions;
Step 2:智能支出分类
银行流水最大的问题是:交易摘要只告诉你"转出50元",但不会告诉你这是"餐饮"还是"交通"。我们需要建立一个分类规则引擎:
-- 创建分类规则表
CREATE TABLE category_rules AS
SELECT * FROM (VALUES
('餐饮', '%外卖%'),
('餐饮', '%美团%'),
('餐饮', '%饿了么%'),
('餐饮', '%麦当劳%'),
('餐饮', '%肯德基%'),
('餐饮', '%星巴克%'),
('交通', '%滴滴%'),
('交通', '%地铁%'),
('交通', '%公交%'),
('购物', '%淘宝%'),
('购物', '%京东%'),
('购物', '%拼多多%'),
('购物', '%沃尔玛%'),
('娱乐', '%爱奇艺%'),
('娱乐', '% Netflix%'),
('娱乐', '%电影%'),
('娱乐', '%KTV%'),
('住房', '%房租%'),
('住房', '%物业%'),
('住房', '%水电%'),
('医疗', '%医院%'),
('医疗', '%药房%'),
('教育', '%学费%'),
('教育', '%培训%'),
('工资', '%工资%'),
('工资', '%奖金%'),
('投资', '%基金%'),
('投资', '%股票%'),
('转账', '%转账%'),
('退款', '%退款%'),
('退款', '%返还%')
) AS t(category_keyword, pattern);
-- 为每笔交易打上分类标签
CREATE TABLE classified_transactions AS
SELECT
t.*,
COALESCE(
(SELECT r.category_keyword
FROM category_rules r
WHERE t.交易摘要 ILIKE r.pattern
LIMIT 1),
'其他'
) AS category
FROM all_transactions t;
扩展分类规则
随着使用深入,你可以不断补充分类规则。比如发现某家餐厅总是被误分类,就加一条规则:
-- 新增分类规则
INSERT INTO category_rules (category_keyword, pattern) VALUES
('餐饮', '%海底捞%'),
('餐饮', '%西贝%'),
('健身', '%Keep%'),
('健身', '%健身房%');
Step 3:月度支出分析
有了分类后的数据,就可以生成各种维度的分析报告:
-- 按类别汇总月度支出
SELECT
category,
SUM(交易金额) AS total_spent,
COUNT(*) AS transaction_count,
AVG(交易金额) AS avg_amount,
ROUND(100.0 * SUM(交易金额) / SUM(SUM(交易金额)) OVER(), 1) AS percentage
FROM classified_transactions
WHERE 交易金额 < 0 -- 支出为负数
GROUP BY category
ORDER BY total_spent DESC;
输出示例:
| category | total_spent | transaction_count | avg_amount | percentage |
|---|---|---|---|---|
| 住房 | -4500.00 | 1 | 4500.00 | 45.0 |
| 餐饮 | -2800.50 | 87 | 32.19 | 28.0 |
| 交通 | -680.00 | 45 | 15.11 | 6.8 |
| 购物 | -1200.00 | 23 | 52.17 | 12.0 |
| 娱乐 | -450.00 | 12 | 37.50 | 4.5 |
| 其他 | -369.50 | 15 | 24.63 | 3.7 |
同比分析:这个月比上个月多花了多少?
-- 按月分组,对比相邻月份支出变化
WITH monthly_spending AS (
SELECT
strftime(交易日期, '%Y-%m') AS month,
category,
SUM(ABS(交易金额)) AS total_spent
FROM classified_transactions
WHERE 交易金额 < 0
GROUP BY strftime(交易日期, '%Y-%m'), category
),
with_change AS (
SELECT *,
LAG(total_spent) OVER (PARTITION BY category ORDER BY month) AS prev_month_spent,
ROUND(total_spent - LAG(total_spent) OVER (PARTITION BY category ORDER BY month), 2) AS change_amount,
ROUND(100.0 * (total_spent - LAG(total_spent) OVER (PARTITION BY category ORDER BY month))
/ NULLIF(LAG(total_spent) OVER (PARTITION BY category ORDER BY month), 0), 1) AS change_pct
FROM monthly_spending
)
SELECT month, category, total_spent, change_amount, change_pct
FROM with_change
WHERE month = (SELECT MAX(month) FROM monthly_spending)
ORDER BY total_spent DESC;
预算管理:有没有超支?
-- 设定月度预算并检查超支情况
CREATE TABLE budgets AS
SELECT * FROM (VALUES
('餐饮', 3000.00),
('交通', 800.00),
('购物', 1500.00),
('娱乐', 500.00),
('住房', 5000.00),
('医疗', 500.00),
('其他', 500.00)
) AS t(category, budget_amount);
-- 检查本月各类别是否超支
SELECT
b.category,
b.budget_amount,
COALESCE(s.total_spent, 0) AS actual_spent,
b.budget_amount - COALESCE(s.total_spent, 0) AS remaining,
CASE
WHEN COALESCE(s.total_spent, 0) > b.budget_amount THEN '⚠️ 已超支'
WHEN COALESCE(s.total_spent, 0) > b.budget_amount * 0.8 THEN '🔔 接近上限'
ELSE '✅ 正常'
END AS status
FROM budgets b
LEFT JOIN (
SELECT category, SUM(ABS(交易金额)) AS total_spent
FROM classified_transactions
WHERE 交易金额 < 0
GROUP BY category
) s ON b.category = s.category
ORDER BY remaining ASC;
Step 4:自动生成月度财务报告
把上面的分析整合成一个完整的月度报告,可以用 Python 脚本自动执行:
import duckdb
from pathlib import Path
from datetime import datetime
def generate_monthly_report(year_month: str):
"""生成指定月份的财务报告"""
con = duckdb.connect(':memory:')
# 1. 导入数据
con.execute(f"""
CREATE TABLE all_transactions AS
SELECT '招商银行' AS bank, * FROM read_csv_auto(
'{Path.home()}/Downloads/CMB_{year_month}.csv', header=true)
UNION ALL
SELECT '支付宝' AS bank, * FROM read_csv_auto(
'{Path.home()}/Downloads/ALIPAY_{year_month}.csv', header=true);
""")
# 2. 分类(复用上面的分类规则)
con.execute("""
CREATE TABLE category_rules AS
SELECT * FROM (VALUES
('餐饮', '%外卖%'), ('餐饮', '%美团%'), ('餐饮', '%饿了么%'),
('交通', '%滴滴%'), ('交通', '%地铁%'),
('购物', '%淘宝%'), ('购物', '%京东%'),
('娱乐', '%爱奇艺%'), ('娱乐', '%电影%'),
('住房', '%房租%'), ('住房', '%物业%'),
('工资', '%工资%'), ('工资', '%奖金%'),
('投资', '%基金%'), ('投资', '%股票%'),
('退款', '%退款%'), ('退款', '%返还%')
) AS t(category_keyword, pattern);
""")
con.execute("""
CREATE TABLE classified AS
SELECT t.*, COALESCE(
(SELECT r.category_keyword FROM category_rules r
WHERE t.交易摘要 ILIKE r.pattern LIMIT 1), '其他'
) AS category
FROM all_transactions t;
""")
# 3. 生成报告
print(f"{'='*50}")
print(f"📊 {year_month} 月度财务分析报告")
print(f"{'='*50}")
# 收入支出概览
overview = con.execute("""
SELECT
SUM(CASE WHEN 交易金额 >= 0 THEN 交易金额 ELSE 0 END) AS income,
SUM(CASE WHEN 交易金额 < 0 THEN ABS(交易金额) ELSE 0 END) AS expense,
SUM(交易金额) AS net_savings
FROM classified
").fetchone()
print(f"\n💰 收入: ¥{overview[0]:,.2f}")
print(f"💸 支出: ¥{overview[1]:,.2f}")
print(f"📈 净储蓄: ¥{overview[2]:,.2f} ({overview[2]/overview[0]*100:.1f}%)")
# 支出分类排行
print(f"\n📋 支出分类 TOP 5:")
top_spending = con.execute("""
SELECT category, SUM(ABS(交易金额)) AS total
FROM classified WHERE 交易金额 < 0
GROUP BY category ORDER BY total DESC LIMIT 5
").fetchall()
for i, (cat, amt) in enumerate(top_spending, 1):
print(f" {i}. {cat}: ¥{amt:,.2f}")
# 高频消费商户
print(f"\n🏪 高频消费商户 TOP 5:")
top_merchants = con.execute("""
SELECT 交易摘要, COUNT(*) AS cnt, SUM(ABS(交易金额)) AS total
FROM classified WHERE 交易金额 < 0
GROUP BY 交易摘要 ORDER BY cnt DESC LIMIT 5
").fetchall()
for i, (merch, cnt, total) in enumerate(top_merchants, 1):
print(f" {i}. {merch}: {cnt}次, ¥{total:,.2f}")
print(f"\n{'='*50}")
con.close()
# 使用示例
generate_monthly_report('202609')
运行结果示例:
==================================================
📊 202609 月度财务分析报告
==================================================
💰 收入: ¥15,000.00
💸 支出: ¥9,900.00
📈 净储蓄: ¥5,100.00 (34.0%)
📋 支出分类 TOP 5:
1. 住房: ¥4,500.00
2. 餐饮: ¥2,800.50
3. 购物: ¥1,200.00
4. 交通: ¥680.00
5. 娱乐: ¥450.00
🏪 高频消费商户 TOP 5:
1. 美团外卖: 32次, ¥1,280.00
2. 滴滴出行: 18次, ¥540.00
3. 淘宝商城: 8次, ¥890.00
4. 饿了么: 15次, ¥620.00
5. 京东商城: 5次, ¥310.00
==================================================
与传统工具对比
| 维度 | Excel 手工记账 | 记账 App | DuckDB 自动化 |
|---|---|---|---|
| 数据导入 | 手动输入或复制粘贴 | 手动输入 | 银行 CSV 一键导入 |
| 多账户聚合 | 需要在多个表格间切换 | 仅支持单一账户 | UNION ALL 多表合并 |
| 支出分类 | 手工标记每笔消费 | App 自动分类但不可定制 | SQL 规则引擎,可自由扩展 |
| 隐私安全 | 文件存本地,较安全 | 数据上传云端,有泄露风险 | 完全本地,数据不出门 |
| 分析灵活性 | 受限于 Excel 功能 | 只能看 App 提供的图表 | SQL 任意维度分析 |
| 自动化程度 | 低,需要手动操作 | 中,但分析受限 | 高,脚本一键生成报告 |
| 学习成本 | 低 | 零 | 中等(会基础 SQL 即可) |
| 费用 | 免费 | 部分功能收费 | 完全免费 |
核心价值:为什么用 DuckDB?
- 零安装:
pip install duckdb即可,无需数据库服务器 - 极速:列式存储 + 向量化执行,百万级流水秒级分析
- 本地优先:所有数据在本地,不涉及任何网络传输,隐私无忧
- SQL 即战力:不需要学新的 API,标准 SQL 就能完成 90% 的分析需求
- 可扩展:随着数据积累,可以轻松扩展到年度分析、跨月对比、趋势预测
📈 变现建议
将这套个人财务分析系统产品化,有以下几种变现路径:
低门槛(免费/低成本启动)
- 模板销售:将分类规则、SQL 查询模板打包成"财务分析模板包",在 Gumroad 或小红书售卖(¥19.9-49.9)
- 教程变现:制作"DuckDB 个人财务自动化"系列视频教程,在 B站/YouTube 发布,通过广告和付费课程变现
- 付费咨询:为不懂技术的用户提供"数据导入+分类配置"的一站式服务,单次收费 ¥100-300
中等投入(需要一些开发/运营)
- SaaS 化财务仪表盘:基于 DuckDB + Streamlit 搭建 Web 应用,用户上传银行 CSV 即可自动生成可视化报告,订阅制 ¥29/月
- 多用户版本:支持夫妻/家庭成员共享财务数据,实时同步分析结果,年费 ¥199/家庭
- 企业版:为小微企业提供员工报销数据分析、团队预算管理等 SaaS 服务,客单价 ¥500-2000/月
高投入(需要团队/资金)
- AI 智能财务顾问:接入 LLM,用自然语言回答问题(“我这个月餐饮花了多少?比上月多了吗?"),DuckDB 负责数据查询,LLM 负责解释结果
- 财务数据平台:聚合多银行 API(通过 OAuth 授权),实现自动同步和实时分析,对标 MoneyWiz、YNAB 等商业产品
- 白标解决方案:为理财顾问/财务规划师提供白标分析平台,按客户数收费 ¥50-200/人/月
总结
DuckDB 让个人财务分析从"手动记账"升级为"自动化智能分析”。你只需要每月下载一次银行 CSV,一条 SQL 就能完成从数据导入、智能分类到报告生成的全流程。所有数据留在本地,隐私有保障,分析无上限。
从今天开始,试着导入你的银行流水,用 DuckDB 看看这个月钱都花哪儿了。