Evidence:SQL + Markdown 生成数据报告网站¶
为什么要学 Evidence¶
数据分析的最后一公里问题——你写了 SQL 得到了结果,但要把它变成好看的报告、仪表板或数据文档,往往需要在 BI 工具中反复拖拽配置,或者用 Python 写大量可视化代码。
Evidence 的理念是:用写文档的方式做数据报告。你只需要在 Markdown 文件中嵌入 SQL 查询,Evidence 会自动执行查询、渲染图表、生成一个静态网站。就像 "Jekyll for data reporting"。
核心价值: - 写 Markdown + SQL 就能生成专业级数据报告网站 - 代码即报告:可以用 Git 做版本管理、Code Review - 零配置图表:SQL 结果自动匹配最佳图表类型 - 部署简单:输出静态文件,可以部署到任何地方 - 支持参数化报告和交互式组件
适用场景: - 周报/月报自动化 - 公司内部数据仪表板 - 面向客户的数据文档 - KPI 监控页面 - 数据团队的分析博客
核心概念¶
白话解释¶
| 概念 | 白话说明 |
|---|---|
| Page | 一个 Markdown 文件就是一个页面/报告 |
| SQL Query | 在 Markdown 中用代码块写 SQL,Evidence 自动执行并命名结果集 |
| Component | 内置的可视化组件(图表、表格、KPI卡片等) |
| Data Source | 连接的数据源(PostgreSQL、BigQuery、DuckDB等) |
| Templated Page | 参数化页面,一个模板生成多个页面 |
| Universal SQL | Evidence 支持的 SQL 方言,跨数据源兼容 |
| Build | 将 Markdown 编译为静态 HTML 网站的过程 |
Evidence 的工作流程¶
编写 Markdown + SQL
│
▼
Evidence 开发服务器 (实时预览)
│
▼
执行 SQL → 获取数据 → 渲染图表 → 生成页面
│
▼
evidence build → 静态网站 → 部署
支持的数据源¶
| 数据源 | 说明 |
|---|---|
| DuckDB | 内置,可直接查询 CSV/Parquet |
| PostgreSQL | 生产数据库 |
| MySQL | 生产数据库 |
| BigQuery | Google 云数据仓库 |
| Snowflake | 云数据仓库 |
| SQLite | 轻量级本地数据库 |
| Databricks | Spark SQL |
| Trino/Presto | 联邦查询 |
| CSV/Parquet | 本地文件(通过 DuckDB) |
安装配置¶
系统要求¶
- Node.js 18+
- npm 或 pnpm
创建项目¶
# 使用官方脚手架
npx degit evidence-dev/template my-report
cd my-report
# 安装依赖
npm install
# 启动开发服务器
npm run dev
浏览器打开 http://localhost:3000 即可看到示例报告。
配置数据源¶
手动配置示例(PostgreSQL):
# evidence.plugins.yaml
datasources:
- postgres:
host: localhost
port: 5432
database: analytics
user: readonly
password: ${POSTGRES_PASSWORD} # 使用环境变量
本地 CSV 文件(使用内置 DuckDB):
# 将 CSV 文件放在 sources/ 目录下
mkdir -p sources/local
cp sales_data.csv sources/local/
# Evidence 会自动将它注册为可查询的表
快速上手¶
第一个报告页面¶
创建 pages/index.md:
---
title: 销售仪表板
---
# 销售概览
```sql sales_summary
SELECT
date_trunc('month', order_date) as month,
COUNT(*) as order_count,
SUM(amount) as revenue
FROM orders
GROUP BY 1
ORDER BY 1
```
<LineChart
data={sales_summary}
x=month
y=revenue
title="月度收入趋势"
/>
## 关键指标
<BigValue
data={sales_summary}
value=revenue
title="总收入"
fmt="$#,##0"
/>
<BigValue
data={sales_summary}
value=order_count
title="总订单数"
/>
## 明细数据
<DataTable data={sales_summary} rows=10 />
使用本地 CSV 数据¶
将 CSV 放入 sources/ 目录后:
```sql csv_data
SELECT * FROM local.sales_data
WHERE region = 'East'
ORDER BY revenue DESC
LIMIT 20
```
<BarChart data={csv_data} x=product y=revenue />
页面路由¶
pages/
├── index.md → /
├── sales.md → /sales
├── customers/
│ ├── index.md → /customers
│ └── [id].md → /customers/123 (参数化)
└── reports/
└── monthly.md → /reports/monthly
进阶用法¶
1. 丰富的图表类型¶
## 折线图
<LineChart data={query_result} x=date y=value />
## 面积图
<AreaChart data={query_result} x=date y={["sales", "costs"]} />
## 柱状图
<BarChart data={query_result} x=category y=count sort=true />
## 散点图
<ScatterPlot data={query_result} x=price y=rating size=volume />
## 饼图
<PieChart data={query_result} name=category value=percentage />
## 漏斗图
<FunnelChart data={funnel_data} name=stage value=users />
## 热力图
<Heatmap data={query_result} x=day y=hour value=count />
## 地图
<USMap data={state_data} state=state_name value=population />
2. 参数化报告¶
---
title: 客户详情
---
# 客户 {params.customer_id} 的详情
```sql customer_info
SELECT * FROM customers
WHERE customer_id = '${params.customer_id}'
```
```sql customer_orders
SELECT * FROM orders
WHERE customer_id = '${params.customer_id}'
ORDER BY order_date DESC
```
<DataTable data={customer_info} />
## 订单历史
<LineChart data={customer_orders} x=order_date y=amount />
文件名为 [customer_id].md,访问 /customers/CUST001 时自动传参。
3. 交互式筛选¶
```sql all_regions
SELECT DISTINCT region FROM sales ORDER BY region
```
<Dropdown
name=selected_region
data={all_regions}
value=region
title="选择区域"
/>
```sql filtered_sales
SELECT * FROM sales
WHERE region = '${inputs.selected_region}'
```
<BarChart data={filtered_sales} x=product y=revenue />
4. 条件渲染¶
```sql revenue_check
SELECT SUM(revenue) as total FROM sales WHERE month = current_month
```
{#if revenue_check[0].total > 1000000}
<Alert status="success">本月收入已超百万!</Alert>
{:else}
<Alert status="warning">本月收入未达标</Alert>
{/if}
5. 循环生成内容¶
```sql departments
SELECT DISTINCT department FROM employees ORDER BY department
```
{#each departments as dept}
## {dept.department} 部门
```sql dept_stats
SELECT COUNT(*) as headcount, AVG(salary) as avg_salary
FROM employees WHERE department = '${dept.department}'
```
- 人数: {dept_stats[0].headcount}
- 平均薪资: {fmt(dept_stats[0].avg_salary, '$#,##0')}
{/each}
6. 自定义样式和布局¶
<Grid cols=3>
<BigValue data={kpi1} value=metric title="DAU" />
<BigValue data={kpi2} value=metric title="收入" fmt="$#,##0" />
<BigValue data={kpi3} value=metric title="转化率" fmt="0.0%" />
</Grid>
<Tabs>
<Tab label="日视图">
<LineChart data={daily} x=date y=value />
</Tab>
<Tab label="周视图">
<LineChart data={weekly} x=week y=value />
</Tab>
</Tabs>
7. 构建与部署¶
# 构建静态网站
npm run build
# 输出在 build/ 目录,可以部署到:
# - Vercel
# - Netlify
# - GitHub Pages
# - 任何静态文件服务器
# 预览构建结果
npm run preview
部署到 Vercel:
8. 定时刷新数据¶
# 使用 GitHub Actions 定时重建
# .github/workflows/refresh.yml
name: Refresh Report
on:
schedule:
- cron: '0 8 * * *' # 每天早8点
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run build
env:
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
- uses: actions/upload-pages-artifact@v3
with:
path: build
常见问题¶
Q1: Evidence 和 Superset/Metabase 有什么区别¶
| 维度 | Evidence | Superset/Metabase |
|---|---|---|
| 工作方式 | Code as Report | 拖拽式 BI |
| 版本管理 | Git 原生 | 数据库存储配置 |
| 协作方式 | Pull Request | 在线编辑 |
| 部署 | 静态文件 | 需要后端服务器 |
| 实时交互 | 有限 | 强 |
| 定制化 | 高(写代码) | 中(配置) |
| 学习曲线 | 会 SQL + Markdown 即可 | 需要学 BI 工具 |
Q2: 数据安全性如何保证¶
- 构建时执行 SQL,输出是静态 HTML
- 生产环境不直连数据库
- 敏感数据可以在查询层面做过滤
- 支持环境变量管理数据库凭证
- 可以加访问控制(Vercel password protection等)
Q3: 能处理大数据量吗¶
- Evidence 在构建时执行查询,不受浏览器内存限制
- 建议在 SQL 层做聚合,不要 SELECT * 百万行
- DuckDB 数据源可以高效处理 GB 级 CSV/Parquet
Q4: 如何调试 SQL 错误¶
Q5: 能嵌入到现有网站吗¶
Evidence 输出标准 HTML/CSS/JS,可以: - 使用 iframe 嵌入 - 直接部署为子路径 - 通过反向代理集成
参考资源¶
| 资源 | 链接 |
|---|---|
| 官方网站 | https://evidence.dev |
| GitHub 仓库 | https://github.com/evidence-dev/evidence |
| 文档 | https://docs.evidence.dev |
| 组件库 | https://docs.evidence.dev/components |
| 示例报告 | https://evidence.dev/examples |
| 社区模板 | https://github.com/evidence-dev/template |
小结: Evidence 把"写报告"这件事回归到了工程师最舒服的方式——写代码。SQL 负责数据逻辑,Markdown 负责叙事结构,组件负责可视化。如果你厌倦了在 BI 工具中反复拖拽,或者想让数据报告享受 Git 工作流的所有好处(版本管理、Code Review、CI/CD),Evidence 是目前最成熟的选择。