Featured image of post Build an E-commerce Weekly Report Automation System with DuckDB

Build an E-commerce Weekly Report Automation System with DuckDB

Learn how to build an automated e-commerce weekly report system using DuckDB: from CSV reading to report generation, with complete Python code, week-over-week analysis, and retention metrics. Turn this into a production-ready data product

Introduction: What’s Your Time Worth?

Do you also experience this scenario—every Monday morning, opening Excel, manually copying last weekend’s sales data, piecing together a report, then sending it to your boss. After that, your boss says “add a few more dimensions,” and you have to start over.

If you automate this workflow with DuckDB, the same work goes from one day to 10 minutes, generates automatically every week, and never makes mistakes. More importantly—this system is ready for production deployment.

Today I’ll walk through a real paid project: building an automated e-commerce weekly report system using DuckDB + Python. I’ve used this methodology for three e-commerce clients, charging each 3000-5000 RMB per month.

1. Project Architecture: Why DuckDB?

Traditional approach: Python script → MySQL → Airflow → Jupyter → Email. Long development cycle, high maintenance cost, no DBA at the client side.

DuckDB approach: Python + DuckDB, one script does it all, zero operations.

Four key advantages of DuckDB:

  1. Analytics performance接近列式数据库: Columnar storage architecture, aggregation 10x faster than pandas
  2. Read CSV/JSON/Parquet in-place: No ETL needed, just read_csv_auto() to load
  3. Seamless Python integration: duckdb library executes SQL directly, results convert to pandas
  4. Single-file database: Copy and use anywhere, deployment cost approaches zero

2. Building the Data Pipeline: From CSV to DuckDB

Assume the e-commerce platform exports CSV files containing orders, products, and users tables.

import duckdb
import pandas as pd
from pathlib import Path
from datetime import datetime, timedelta

# Connect to DuckDB database (persistent storage)
db_path = Path("ecommerce.duckdb")
con = duckdb.connect(str(db_path))

# Read CSV in-place (no need to load into memory first)
con.execute("""
 CREATE TABLE IF NOT EXISTS orders AS 
 SELECT * FROM read_csv_auto('orders.csv')
""")
con.execute("""
 CREATE TABLE IF NOT EXISTS products AS 
 SELECT * FROM read_csv_auto('products.csv')
""")
con.execute("""
 CREATE TABLE IF NOT EXISTS users AS 
 SELECT * FROM read_csv_auto('users.csv')
""")

# Check table structure
print(con.execute("DESCRIBE orders").fetchdf())
print(con.execute("SELECT COUNT(*) FROM orders").fetchone())

Key points:

  • read_csv_auto() automatically infers column types, no manual specification needed
  • CREATE TABLE IF NOT EXISTS ensures idempotency, safe to run repeatedly
  • DuckDB reads CSV directly, no need to import into database first

3. Core Analysis Logic: Weekly Report Metric Design

The core of a weekly report is metric tree design, making it understandable for non-technical clients.

# Create weekly sales view (auto-slices by week)
con.execute("""
CREATE VIEW IF NOT EXISTS v_weekly_sales AS
SELECT 
 DATE_TRUNC('week', order_date) AS week,
 COUNT(*) AS total_orders,
 SUM(amount) AS total_revenue,
 AVG(amount) AS avg_order_value,
 COUNT(DISTINCT user_id) AS active_users,
 COUNT(DISTINCT product_id) AS unique_products
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '12 weeks'
GROUP BY DATE_TRUNC('week', order_date)
ORDER BY week DESC
""")

# Verify view
print(con.execute("SELECT * FROM v_weekly_sales LIMIT 5").fetchdf())

Metric design principles:

  • Put core metrics first: orders, revenue, average order value, active users
  • Add week-over-week comparison: clients can see trends at a glance
  • Keep 12 weeks of data: sufficient, doesn’t waste storage

4. Generating Weekly Reports: Complete Python Code

def generate_weekly_report(db_path: str) -> dict:
 """Generate weekly business report"""
 con = duckdb.connect(db_path)
 
 # Get current week and previous week data
 current_week = con.execute("""
 SELECT * FROM v_weekly_sales 
 WHERE week = DATE_TRUNC('week', CURRENT_DATE)
 """).fetchone()
 
 prev_week = con.execute("""
 SELECT * FROM v_weekly_sales 
 WHERE week = (
 SELECT MAX(week) FROM v_weekly_sales 
 WHERE week < DATE_TRUNC('week', CURRENT_DATE)
 )
 """).fetchone()
 
 # Week-over-week calculation function
 def pct_change(curr, prev):
 if prev is None or prev == 0: 
 return None
 return round((curr - prev) / prev * 100, 2)
 
 report = {
 "week": current_week[0].strftime('%Y-%m-%d') if current_week else None,
 "total_orders": current_week[1] if current_week else 0,
 "total_revenue": round(current_week[2], 2) if current_week else 0,
 "revenue_growth": pct_change(current_week[2], prev_week[2]) if current_week and prev_week else None,
 "avg_order_value": round(current_week[3], 2) if current_week else 0,
 "avg_order_growth": pct_change(current_week[3], prev_week[3]) if current_week and prev_week else None,
 "active_users": current_week[4] if current_week else 0,
 "user_growth": pct_change(current_week[4], prev_week[4]) if current_week and prev_week else None,
 }
 
 # Top 5 categories by revenue
 report["top_categories"] = con.execute("""
 SELECT p.category, SUM(o.amount) as revenue
 FROM orders o 
 JOIN products p ON o.product_id = p.id
 WHERE DATE_TRUNC('week', o.order_date) = DATE_TRUNC('week', CURRENT_DATE)
 GROUP BY p.category
 ORDER BY revenue DESC
 LIMIT 5
 """).fetchall()
 
 # User retention analysis (window functions)
 report["retention"] = con.execute("""
 SELECT 
 first_week,
 COUNT(DISTINCT user_id) as new_users,
 SUM(CASE WHEN weeks_active >= 2 THEN 1 ELSE 0 END) as retained_2w,
 SUM(CASE WHEN weeks_active >= 3 THEN 1 ELSE 0 END) as retained_3w
 FROM (
 SELECT 
 user_id,
 DATE_TRUNC('week', MIN(order_date)) as first_week,
 COUNT(DISTINCT DATE_TRUNC('week', order_date)) as weeks_active
 FROM orders
 WHERE order_date >= CURRENT_DATE - INTERVAL '12 weeks'
 GROUP BY user_id
 )
 GROUP BY first_week
 ORDER BY first_week DESC
 LIMIT 4
 """).fetchall()
 
 con.close()
 return report

5. Exporting Reports: Multiple Formats for Different Scenarios

import json
from pathlib import Path

def export_report(report: dict, output_dir: str):
 """Export in multiple formats"""
 out = Path(output_dir)
 out.mkdir(parents=True, exist_ok=True)
 
 # JSON format (for API calls)
 (out / "report.json").write_text(
 json.dumps(report, ensure_ascii=False, indent=2)
 )
 
 # Markdown format (can be sent directly via WeChat/Feishu)
 md = f"""# Weekly Report {report['week']}

## Core Metrics
- **Orders**: {report['total_orders']:,} ({'↑' if report['revenue_growth'] and report['revenue_growth'] > 0 else '↓'} {abs(report['revenue_growth']):.1f}%)
- **Revenue**: ${report['total_revenue']:,.2f} ({'↑' if report['revenue_growth'] and report['revenue_growth'] > 0 else '↓'} {abs(report['revenue_growth']):.1f}%)
- **Avg Order Value**: ${report['avg_order_value']:.2f} ({'↑' if report['avg_order_growth'] and report['avg_order_growth'] > 0 else '↓'} {abs(report['avg_order_growth']):.1f}%)
- **Active Users**: {report['active_users']:,}

## Top 5 Categories
"""
 for i, (cat, rev) in enumerate(report['top_categories'], 1):
 md += f"{i}. {cat}: ${rev:,.2f}\n"
 
 (out / "report.md").write_text(md)
 print(f"✅ Report generated: {out}")

# Usage example
if __name__ == "__main__":
 report = generate_weekly_report("ecommerce.duckdb")
 export_report(report, "reports/2026-W31")

6. Complete Workflow: One-Click Weekly Report Generation

# main.py
from pathlib import Path
import duckdb
from datetime import datetime

def main():
 # 1. Load data (idempotent)
 con = duckdb.connect("ecommerce.duckdb")
 
 # Auto incremental update
 csv_files = list(Path("data").glob("orders_*.csv"))
 for f in sorted(csv_files)[-1:]: # Only load the latest file
 con.execute(f"INSERT INTO orders SELECT * FROM read_csv_auto('{f}')")
 
 # 2. Generate report
 report = generate_weekly_report("ecommerce.duckdb")
 
 # 3. Export
 week_str = report['week'].replace('-', '')
 export_report(report, f"reports/{week_str}")
 
 con.close()
 print("🎉 Weekly report generated")

if __name__ == "__main__":
 main()

8. Comparison with Traditional Approaches

DimensionTraditional (MySQL + Airflow)DuckDB Approach
Development cycle2-4 weeks1-2 days
Maintenance costNeed DBAZero ops
Deployment costServer + databaseSingle machine
Query performanceNeed indexesColumnar storage, ready to use
Data updateComplex ETL pipelineCSV direct read, plug and play
PortabilityTied to specific databaseSingle file, copy and use

9. Real Case: What I Charged My Client

Last month, I built this system for an e-commerce client:

  • Data source: Shopify exported CSV, about 300K rows/month
  • Metrics: Orders, revenue, average order value, active users, retention rate
  • Deliverable: Automatically sent Markdown report every week
  • Fee: One-time 8000 RMB + monthly maintenance 2000 RMB/month

Client feedback: “Much faster than the outsourced solution I had before, and easier to modify.”

10. Summary

Building an e-commerce weekly report automation system with DuckDB comes down to three steps:

  1. Read data: read_csv_auto()搞定 with one line of code
  2. Calculate metrics: Window functions + views, SQL = analytics
  3. Export reports: Python formatting, dual Markdown/JSON formats

This methodology can be replicated to:

  • Financial monthly reports
  • Ad spend ROI tracking
  • SaaS subscription analysis
  • Inventory warning systems

Remember: The value of data products lies not in technology, but in business understanding. The same code, applied to a different industry, becomes another product.


📖 The complete tutorial (including data simulation, anomaly detection, Streamlit deployment) is published on duckdblab.org. Bookmark it for systematic learning.

💡 Want to learn more about DuckDB applications in e-commerce? duckdblab.org has a complete practical tutorial series, covering everything from beginner to .


本文信息

项目内容
DuckDB 版本v1.5.x(部分功能基于 v2.0 Preview)
最后验证2026-09-12
测试环境Linux / x86_64 / 16GB RAM
官方文档DuckDB Documentation
GitHubpengzz9527/duckdb-blog

如发现错误,欢迎通过 GitHub Issue 或邮件 contact@duckdblab.org 反馈。

📺 Watch video tutorials → Olap Studio YouTube

Subscribe for more DuckDB & AI automation tutorials