Featured image of post DuckDB 电商日报实战:5 条 SQL 搞定自动化销售报表,每月收 99 元

DuckDB 电商日报实战:5 条 SQL 搞定自动化销售报表,每月收 99 元

用 DuckDB 搭建全自动电商日报系统,5 条核心 SQL 查询实现销售总览、品类分析、城市热力、复购率和环比对比,自动化部署后按 SaaS 模式每月向电商卖家收取订阅费。

DuckDB 电商日报实战:5 条 SQL 搞定自动化销售报表

如果你靠数据分析接外包,每天最头疼的事不是写 SQL,而是每天重复跑同一套报表:给客户的老板看昨日销售汇总、品类排行、城市热度、复购趋势……这套流程做一单收费 500-2000 块,但每次都要花 1-2 小时手工处理。

今天拆解一个真实可复现的项目:用 DuckDB 构建一套全自动电商日报系统,从数据采集到可视化报表一键生成。做完之后,这个系统可以卖给任何电商卖家,按 SaaS 模式每月收 99 元/月。

电商日报系统架构


一、项目架构:3 个文件搞定整套系统

整个系统只需 3 个文件:

  1. generate_report.py —— 核心报告生成脚本
  2. daily_report.md.j2 —— Jinja2 模板
  3. config.yaml —— 配置文件

不需要数据库,不需要 Web 框架。 DuckDB 直接读 CSV/Parquet,用 Jinja2 生成 Markdown,用 SMTP 发邮件。

系统数据流如下:

订单 CSV → DuckDB (直接读取) → 5 条 SQL 查询 → Jinja2 模板 → Markdown 日报 → 邮件发送

完整 SQL 查询只需 5 条核心语句,下面逐条拆解。


二、核心查询 1:实时销售总览

第一步,用一条查询算出当天的关键 KPI。

SELECT
    COUNT(*) AS total_orders,
    ROUND(SUM(amount), 2) AS total_revenue,
    ROUND(AVG(amount), 2) AS avg_order_value,
    COUNT(DISTINCT customer) AS unique_customers,
    MAX(order_date) AS latest_order_date
FROM sales
WHERE order_date = CURRENT_DATE;

这条查询的返回值就是你每天报表最开头的 KPI 卡片:

📊 昨日销售总览 (2026-06-09)
━━━━━━━━━━━━━━━━━━━━━━━━━━
📦 订单总数:42 单
💰 总销售额:¥186,420.00
🎯 平均客单价:¥4,438.57
👥 独立客户:38 人

变现要点:很多电商卖家用的是千牛/生意参谋自带的看板,但这些工具看不到「独立客户数」「客单价趋势」这类自定义指标。你的日报多这 2-3 个维度,就是客户愿意付费的理由。

与传统工具对比

工具实现时间代码量部署难度适合场景
Excel/VBA2-3 天50+ 行小型店铺,手动更新
Pandas + Jupyter1 天80+ 行数据分析师自用
Power BI3-5 天可视化拖拽需要交互式看板
DuckDB + Python2 小时30 行自动化日报,零运维

三、核心查询 2:品类深度分析

第二步,分析品类的收入贡献和潜力。

WITH category_stats AS (
    SELECT
        category,
        COUNT(*) AS orders,
        ROUND(SUM(amount), 2) AS revenue,
        ROUND(AVG(amount), 2) AS avg_price,
        COUNT(DISTINCT customer) AS customers,
        ROUND(
            SUM(amount) * 100.0 / SUM(SUM(amount)) OVER(), 1
        ) AS revenue_share
    FROM sales
    WHERE order_date = CURRENT_DATE
    GROUP BY category
),
ranked AS (
    SELECT *,
        ROW_NUMBER() OVER (ORDER BY revenue DESC) AS rev_rank,
        ROW_NUMBER() OVER (ORDER BY customers DESC) AS cust_rank
    FROM category_stats
)
SELECT
    category,
    orders,
    revenue,
    avg_price,
    customers,
    revenue_share,
    rev_rank,
    cust_rank
FROM ranked
ORDER BY revenue DESC;

输出示例:

品类收入排行 (2026-06-09)
━━━━━━━━━━━━━━━━━━━━━━━━━━
① 电子产品 — ¥86,390 (占比 46.3%) — 客单价 ¥8,639
② 家电     — ¥35,994 (占比 19.3%) — 客单价 ¥5,999
③ 外设     — ¥10,096 (占比 5.4%)  — 客单价 ¥2,524
④ 个护     — ¥4,598  (占比 2.5%)  — 客单价 ¥2,299

变现要点:这里用到了 DuckDB 的窗口函数 SUM() OVER() 做实时占比计算。这个能力在 MySQL 里也能做但效率差很多,在 Pandas 里需要写 10 行代码。强调这个效率差异,是说服客户从 Excel/Pandas 迁移到 DuckDB 的关键话术。

这里的关键技术点是 窗口函数(Window Functions)SUM() OVER() 让你在不写子查询的情况下计算聚合占比,ROW_NUMBER() 帮你做排名。这些都是 DuckDB 的内置能力,无需额外安装。


四、核心查询 3:城市热力图

第三步,找出高价值城市。

SELECT
    city,
    COUNT(*) AS orders,
    ROUND(SUM(amount), 2) AS total_revenue,
    ROUND(AVG(amount), 2) AS avg_order,
    COUNT(DISTINCT customer) AS unique_customers,
    ROUND(PERCENT_RANK() OVER (ORDER BY total_revenue), 3) AS revenue_percentile,
    ROUND(PERCENT_RANK() OVER (ORDER BY avg_order), 3) AS avg_order_percentile
FROM sales
WHERE order_date = CURRENT_DATE
GROUP BY city
ORDER BY total_revenue DESC
LIMIT 15;

输出示例:

城市价值排行 Top 10
━━━━━━━━━━━━━━━━━━━━━━━━━━
北京   — ¥19,999  (收入百分位: 1.000) 🏆
长沙   — ¥18,999  (收入百分位: 0.950)
上海   — ¥15,999  (收入百分位: 0.900)
大连   — ¥14,999  (收入百分位: 0.850)
宁波   — ¥12,999  (收入百分位: 0.800)

变现要点PERCENT_RANK() 这个函数是 DuckDB 的杀手锏。它帮你快速看出哪个城市虽然订单量不大,但客单价极高——这样的城市值得投放定向广告。很多电商运营需要手动在 Excel 里排序算排名,你一条 SQL 搞定。

DuckDB 的 PERCENT_RANK() vs 传统方法

在传统方案中,算百分位排名需要:

# Pandas 方案:需要多步操作
df['revenue_percentile'] = df['total_revenue'].rank(pct=True)

而 DuckDB 直接用 SQL 完成,一步到位,且可以在查询层面做优化:

-- DuckDB 一行搞定
PERCENT_RANK() OVER (ORDER BY total_revenue)

对于百万级数据,DuckDB 的处理速度通常比 Pandas 快 5-10 倍。


五、核心查询 4:复购率分析

第四步,算复购率——这是电商老板最关心的指标之一。

WITH customer_orders AS (
    SELECT
        customer,
        COUNT(*) AS order_count,
        MIN(order_date) AS first_order,
        MAX(order_date) AS last_order,
        ROUND(SUM(amount), 2) AS total_spent
    FROM sales
    GROUP BY customer
),
repurchase AS (
    SELECT
        COUNT(*) AS total_customers,
        SUM(CASE WHEN order_count > 1 THEN 1 ELSE 0 END) AS repurchase_count
    FROM customer_orders
)
SELECT
    total_customers,
    repurchase_count,
    ROUND(repurchase_count * 100.0 / total_customers, 1) AS repurchase_rate,
    ROUND(avg_clv, 2) AS avg_customer_lifetime_value
FROM repurchase
CROSS JOIN (
    SELECT AVG(total_spent) AS avg_clv
    FROM (
        SELECT SUM(amount) AS total_spent
        FROM sales
        GROUP BY customer
    ) sub
) avg_calc;

输出示例:

🔄 复购分析
━━━━━━━━━━━━━━━━━━━━━━━━━━
👥 总客户数:128 人
🔁 复购客户:23 人 (18.0%)
💎 客户终身价值:¥8,456.32

变现要点:复购率是电商的生命线。18% 的复购率对于一般电商算合格,但如果能做到 30%+,客户就能大幅降低获客成本。这个分析直接关联到 ROI 计算——每提升 1% 的复购率,意味着每月可以多赚多少。

这里用到了 CTE(公用表表达式) 的分步写法。先按客户聚合订单,再统计复购人数,最后计算比率。CTE 让 SQL 逻辑像写代码一样层次分明,比嵌套子查询可读性好太多。


六、核心查询 5:趋势对比(与昨日比)

第五步,做同比——这是日报最有价值的部分,因为它回答了「今天比昨天好还是差」。

WITH today AS (
    SELECT
        COUNT(*) AS orders,
        ROUND(SUM(amount), 2) AS revenue,
        ROUND(AVG(amount), 2) AS avg_order
    FROM sales
    WHERE order_date = CURRENT_DATE
),
yesterday AS (
    SELECT
        COUNT(*) AS orders,
        ROUND(SUM(amount), 2) AS revenue,
        ROUND(AVG(amount), 2) AS avg_order
    FROM sales
    WHERE order_date = CURRENT_DATE - INTERVAL 1 DAY
)
SELECT
    t.orders, t.revenue, t.avg_order,
    y.orders AS prev_orders,
    y.revenue AS prev_revenue,
    y.avg_order AS prev_avg_order,
    ROUND((t.revenue - y.revenue) * 100.0 / NULLIF(y.revenue, 0), 1) AS revenue_change_pct,
    ROUND((t.orders - y.orders) * 100.0 / NULLIF(y.orders, 0), 1) AS orders_change_pct
FROM today t
CROSS JOIN yesterday y;

输出示例:

📈 环比昨日变化
━━━━━━━━━━━━━━━━━━━━━━━━━━
📦 订单量:42 (+12.8%)
💰 销售额:¥186,420 (+8.3%)
🎯 客单价:¥4,438.57 (-3.9%)

变现要点NULLIF() 是 DuckDB 处理除零错误的最佳实践。这条查询看起来简单,但包含了时间序列分析的核心思路——用 CTE 实现自关联对比,不需要任何外部工具。

NULLIF() 的重要性

在 SQL 中,除零是一个经典的陷阱。NULLIF(a, 0) 当 a 为 0 时返回 NULL,这样整个除法的结果就是 NULL 而不是报错。配合 ROUND() 函数,可以让报表在数据为空时依然干净整洁。


七、自动化部署:cron + Python 一键运行

用 cron 每天凌晨 2 点自动生成报告并发送邮件:

# 编辑 crontab
crontab -e

# 添加以下行:每天凌晨 2 点生成并发送日报
0 2 * * * cd /root/telegram-duckdb-bot && python3 generate_report.py --send-email

generate_report.py 的核心逻辑:

import duckdb
import jinja2
import smtplib
from email.mime.text import MIMEText
from datetime import date

# 1. 连接 DuckDB(直接读 Parquet/CSV)
con = duckdb.connect("ecommerce.duckdb")

# 2. 执行所有查询,获取结果
kpi_result = con.execute("""
    SELECT COUNT(*) AS total_orders,
           ROUND(SUM(amount), 2) AS total_revenue,
           ROUND(AVG(amount), 2) AS avg_order_value,
           COUNT(DISTINCT customer) AS unique_customers
    FROM sales
    WHERE order_date = CURRENT_DATE
""").fetchdf()

# 3. 用 Jinja2 模板渲染 Markdown 报告
template = jinja2.Template(open("daily_report.md.j2").read())
report_md = template.render(
    date=date.today(),
    kpi=kpi_result.to_dict('records')[0],
)

# 4. 发送邮件
msg = MIMEText(report_md, 'html', 'utf-8')
msg['Subject'] = f'电商日报 {date.today()}'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'

smtp = smtplib.SMTP('smtp.yourdomain.com', 587)
smtp.starttls()
smtp.login('user', 'password')
smtp.send_message(msg)

整个系统从数据采集到邮件发送,核心代码不超过 50 行。DuckDB 处理 100 万行数据通常只需要 0.5-2 秒,远快于 Pandas 的 3-8 秒。


八、与传统方案的完整对比

下面从多个维度对比这套 DuckDB 方案与传统电商数据分析方案:

维度Excel/手工Pandas + JupyterPower BIDuckDB 日报系统
搭建时间数天半天1-2 周2 小时
维护成本高(每次手动)低(cron 自动)
查询速度慢(>10万行卡顿)快(列式存储)
扩展性好(支持 Parquet)
月成本¥0 + 人力¥0 + 人力¥500+/月¥0 + 服务器 ¥50
适合数据量<10 万行<1000 万行<1 亿行任意(磁盘处理)

九、商业化路径:三种变现方式

这个项目做完后的变现路径非常清晰:

路径 A:卖模板(一次收费 ¥199)

把上面的脚本包装成一个「电商日报自动化模板」,在知识星球/V2EX/掘金等平台分享部分 SQL,完整版模板收费 199 元。

目标用户:电商运营、数据分析师、小型工作室

路径 B:SaaS 服务(持续收入 ¥99/月/店)

把脚本部署到云服务器,做成 Web 产品。客户只需把 CSV 订单上传,每天自动收到 Markdown/PDF 日报。

定价:99 元/月/店,支持多店 目标用户:中小电商卖家(他们请不起专职数据分析师)

路径 C:外包交付(高客单 ¥500-2000/单)

帮客户定制化配置:接入他们的订单系统(如 Shopify、有赞、千牛),定制报表模板,设置自动化邮件。

交付周期:1-2 天 利润率:80%+(主要是 SQL 和 Python 脚本,几乎零边际成本)

路径 D:数据监控即服务(进阶)

在日报基础上增加异常检测:当销售额突然下降超过 20% 时,自动发 Telegram 消息给老板。这个增值功能可以单独收费 ¥49/月。


十、进阶扩展方向

当客户用上基础日报后,可以继续扩展:

  1. 周报/月报:在日报基础上聚合周/月数据,增加同比环比趋势图
  2. 竞品分析:用 httpfs 扩展爬取竞品网站价格数据,用 DuckDB 对比
  3. 客户画像:基于购买记录,用 DuckDB 的 UNNEST 和列表函数分析客户偏好
  4. 可视化升级:把 Markdown 报表对接到 Evidence 或 Grafana,生成交互式看板
  5. 多店铺聚合:用 DuckDB 的 read_parquet + glob 模式,同时处理多个店铺的 Parquet 文件

总结

这套 DuckDB 电商日报系统的核心优势在于:

  • 5 条 SQL 覆盖 90% 的日报需求:销售总览、品类分析、城市热力、复购率、趋势对比
  • 零依赖部署:不需要数据库、Web 框架或 BI 工具
  • 自动化运行:cron + Python 每天自动执行,老板每天醒来就能看到报表
  • 可规模化:从 1 家店扩展到 100 家店,代码几乎不用改

对于数据服务从业者来说,这就是一个标准的「一次开发,反复售卖」的赚钱项目。掌握 DuckDB 在这类场景中的用法,能让你在接外包和做 SaaS 时比别人快 10 倍。


📖 本文的完整版已发布在 duckdblab.org,包含更详细的代码文件、Jinja2 模板和可下载的示例数据集。

💡 想系统学习 DuckDB 在电商分析中的应用?duckdblab.org 上有从入门到变现的完整教程系列,涵盖 Parquet 处理、窗口函数实战、自动化部署等进阶主题。

📺 Watch video tutorials → DuckDB Lab YouTube

Subscribe for more DuckDB & AI automation tutorials

使用 Hugo 构建
主题 StackJimmy 设计