贴一段 SQL,生成一张可独立访问、可导出 Excel 的网页报表
报表查看页:设置条件 → 查询 → KPI 摘要 + 分页表格 → 一键导出 Excel
纯 Python 标准库 · 零 Web 框架依赖 · 一个报表 = 一个 JSON = 一个 URL · 免登录只读分享
| 特性 | 说明 | |
|---|---|---|
| 🔗 | 独立 URL 免登录 | 每张报表一个只读地址 /r/<报表id>,打开即查,用户零门槛 |
| 🧩 | 6 种参数控件 | 文本 / 下拉 / 日期 / 日期范围 / 数字 / 数字范围;支持精确↔范围双模式、字段绑定自动过滤、下拉级联与候选 SQL |
| 🗄️ | 三种数据库 | MySQL / SQL Server / SQLite,驱动按需懒加载,只装你用到的 |
| 🔀 | 多数据集跨源查询 | union 纵向合并 / lookup 横向关联,跨 MySQL 与 SQL Server 拼一张表 |
| 📊 | 内置统计分析 | 合计行 / KPI 摘要 / Top N / 占比与累计 / 时间分桶 / 透视表 / 对比差值 / 数值分箱 |
| 🧱 | 一页多块渲染 | 明细表 + 透视 + 分箱自由组合,一个页面讲清一件事 |
| 📈 | 真 Excel 导出 | 真 .xlsx(多 sheet、数值单元格可计算)与轻量 .xls / .csv,导出所见即页面所得 |
| ⚡ | 大数据量稳定 | 单数据集 10 万行硬顶、fetchmany 分批、TTL+LRU 结果缓存、超限截断提示 |
| 🔐 | 可选安全加固 | HMAC token 按日轮换分享链接、管理面本机保护 / HTTP Basic、只读 SQL 白名单 |
| 📁 | 报表分组目录 | reports/<分组>/<id>.json 支持中文分组,/browse 按分组只读浏览 |
| 报表列表 | 报表编辑器 |
|---|---|
![]() |
![]() |
| 数据源管理 | 透视分析(多块渲染) |
![]() |
![]() |
pip install -e . # 零依赖,秒装(Python ≥ 3.10)
# 按需安装数据库驱动:pip install -e ".[mysql]" 或 ".[mssql]"
cp examples/datasources.example.json datasources.json # 填入真实连接(已被 gitignore)
python -m sqlreport # 默认 0.0.0.0:8765浏览器打开 http://127.0.0.1:8765/,三步出报表:
- 数据源管理 新建连接(或手改
datasources.json,改动免重启生效,支持连接测试) - +新建报表 → 填名称、选数据源、贴 SQL(用
{{参数}}占位)、配置参数控件,可单独试运行 - 保存 即得独立访问 URL
/r/<报表id>—— 分享给同事,查询、导出全程免登录
生产部署:
scripts/start.sh(macOS/Linux,自动建 venv + 装依赖 + 健康检查)、scripts\start.bat(Windows 后台运行),详见 部署。
报表就是 reports/ 下的一份 JSON——随时手改、好备份、可批量生成,没有任何后台数据库。
旧格式 {ds, sql} 零迁移兼容,多数据集自动升级为 datasets 数组:
也可以在编辑器里可视化完成以上一切——参数配置抽屉支持绑定数据集字段(自动生成 WHERE 条件,无需改 SQL)与候选值 SQL(下拉级联取值)。
| 参数类型 | SQL 写法 | 说明 |
|---|---|---|
| 文本/数字/日期/下拉 | AND region = '{{region}}' |
值经转义后替换 |
| 日期范围 | dt >= '{{d.begin}}' AND dt <= '{{d.end}}' |
也支持下划线写法 {{d_begin}} |
| 数字范围 | amt >= '{{n.min}}' AND amt <= '{{n.max}}' |
同上 |
| 可选条件 | 含占位符的整行,参数未填时自动丢弃 | 条件务必独立成行 |
编辑器可添加多个数据集(各自选数据源、写 SQL、单独试运行),≥2 个时可选合并方式:
{
"datasets": [
{"name": "a", "ds": "mysql1", "sql": "SELECT ..."},
{"name": "b", "ds": "mssql1", "sql": "SELECT ..."}
],
// 方式一:纵向合并(按列名对齐,缺失列留空)
"merge": {"mode": "union"}
// 方式二:横向关联(left join 取值,右表 ≤10 万行)
// "merge": {"mode": "lookup", "base": "a", "with": "b", "on": ["cust_id"], "cols": ["cname"]}
}查看页之外,报表可叠加分析块(blocks)与管道配置,全部基于最终返回行集计算:
{
"blocks": [
{"type": "pivot", "dataset": "main", "row": "区域", "col": "渠道",
"value": "金额", "agg": "sum", "title": "区域 × 渠道 销售透视"},
{"type": "hist", "dataset": "main", "col": "金额", "bins": 10, "title": "金额分布"}
],
"top_n": {"col": "金额", "n": 10, "others": "其他"}, // Top N,其余归并一行
"share": {"col": "金额"}, // 追加 占比% / 累计% 列
"bucket": {"col": "下单时间", "unit": "month"}, // 日期分桶:day/week/month/quarter
"compare": {"dataset": "b", "on": ["cust_id"], "metric": "金额", "label": "上月"} // 对比差值
}- 透视表:行 × 列维度聚合(sum/count/avg/max/min),自动行列合计,维度超 50 提示先归类
- 数值分箱:等宽区间统计表(区间 / 计数 / 占比%)
- 对比差值:跨数据集按键对齐,追加「差值」「增长率%」两列(环比语义)
- 查询硬上限:单数据集 fetch 10 万行;每数据源
timeout(秒)超时控制 - 结果缓存:报表级
cache_ttl(key = 报表 id + 参数哈希),保存报表即清空该报表缓存 - 仅
SELECT/WITH单语句可执行(去注释后白名单校验,拒绝多语句)
- 业务库一律使用只读账号;参数值按
''转义后拼接——SQL 作者可信,参数必须防注入 - 公网部署可在
config.json配置{"auth": "token", "token_secret": "…"}启用 HMAC 分享链接鉴权(缺省关闭,内网直用) - 管理页(/datasources)默认仅本机可访问,或配置
admin_password走 HTTP Basic - 建议通过反向代理(Nginx/Caddy)提供 HTTPS
Windows
scripts\start.bat :: 后台启动(端口 8765,日志 logs\sqlreport.log)
scripts\start.bat 9000 :: 指定端口
scripts\stop.bat :: 停止自动探测 python/py/python3,端口占用检查,start /min 后台运行;根目录 start.bat/stop.bat 为薄转发。
macOS / Linux
./scripts/start.sh # 后台启动(端口 8765,日志 logs/sqlreport.log)
./scripts/start.sh 9000 # 指定端口
./scripts/stop.sh # 停止POSIX sh 脚本(bash/dash/zsh 通用):自动探测 Python 3.10+(缺失按发行版提示安装命令)、创建 .venv 并 pip install -e .、缺驱动时交互询问安装、端口占用检查、nohup 后台运行 + curl 健康检查、PID 记入 logs/sqlreport.<端口>.pid。
展开查看
sqlreport/
├── src/sqlreport/ # 源码包(标准 src 布局,唯一可信源码)
│ ├── server.py # 路由 + 鉴权 + 业务编排(统一执行链路)
│ ├── views_report.py # 页面模板与拼装(列表/编辑器/查看页)
│ ├── db.py # 数据层:连接/限流/合并/缓存
│ ├── params.py # 参数层:转义/替换/归一化(纯函数)
│ ├── analytics.py # 统计分析:合计/KPI/TopN/占比/分桶/透视(纯函数)
│ └── xlsx.py # 真 .xlsx 导出(标准库 zip 实现,零依赖)
├── pyproject.toml # 构建元数据(dependencies = [],驱动可选)
├── tests/ # 458 个测试(unittest,零依赖,与源码模块一一对应)
├── scripts/ # 运维脚本(start/stop × sh/bat)
├── examples/ # 配置样例(datasources.example.json)
├── docs/ # 设计/PRD/规划/开发准则 + Code Wiki + 截图
├── reports/*.json # 运行时报表定义(不入库,一文件一报表)
├── datasources.json # 数据源配置(不入库)
└── config.json # 全局配置:鉴权/管理口令(不入库)
- docs/DEVELOPMENT.md —— 开发准则(必读:流程/测试/发布约定)
- docs/DESIGN-v0.2.md / docs/PRD-v0.2.md —— 设计与产品文档
- docs/PLAN.md / docs/CHANGELOG.md —— 规划与变更记录
- docs/wiki/ —— Code Wiki(架构总览 / 模块与关键代码 / HTTP 接口 / 运行部署)
欢迎 Issue 与 PR,约定见 CONTRIBUTING.md、CODE_OF_CONDUCT.md、SECURITY.md。




{ "name": "销售订单汇总", "ds": "mysql1", // 单数据集旧格式;≥2 个数据集时用 datasets + merge "sql": "SELECT region 区域, amount 金额, created_at 下单时间 FROM orders WHERE 1=1 AND created_at >= '{{d.begin}}' AND created_at <= '{{d.end}}' AND region = '{{region}}'", "params": [ // 参数控件定义(6 种类型) {"id": "d", "label": "下单日期", "type": "daterange"}, {"id": "region", "label": "区域", "type": "select", "options": "华东,华南,华北"} ], "cache_ttl": 300, // 结果缓存秒数,0 = 实时 "max_rows": 2000, // 展示行上限,超限截断并提示 "summary": [{"col": "金额", "fn": "sum", "label": "销售额"}], // KPI 摘要 "total": {"label": "合计"} // 合计行 }