水利数据仓查询

水库台账、逐月来水、行政区划、年度供用水统计——原本分别躺在几十个 Excel、几百页 PDF 和一堆 shapefile 里。把它们统一成一组可查询的表,找一个数从「开三个软件翻半天」变成「写一行筛选条件」。

这是可操作的演示:下面的水库名、地名、流域名、所有数字全部是编的,可以随便点、随便导出。 字段结构与计算口径参照真实系统,真实数据一条都不在这里——它在闸后的内网环境里,服务于一家水利设计单位的日常出图与报告编写。

1 · 这套系统解决什么问题

难点几乎全都不在「查询」本身,而在数据进来之前的口径。下面六条是真实踩出来的,演示区里每一条都在跑:

难点为什么难 / 这里怎么处理
一个县在源表里有好几行年报按水资源分区出行,一个县可能跨两三个分区。只读第一行会漏掉一半水量;把所有行无脑求和,又会把「城镇化率」这类比值也加起来。
做法:外延量(人口、水量、产值)求和;比值与人均量在聚合完成之后重算
年年的表头都不一样某一年改走公报汇总表,字段就少了几列。按首年表头去读,要么新增列被静默丢掉,要么直接崩。
做法:列 = 各年字段的并集(按首次出现顺序),某年没有的画「—」,绝不填 0——0 是一个有含义的观测值,缺测不是 0。
一张表里混着两套维度「蓄水/引水/提水/跨流域调水」是取水方式,「地表水/地下水/其他水源」是水源类型,而前四项之和恰好等于地表水。全都拿去算占比,加起来就是 200%。
做法:把子项集合显式登记为常量,占比只沿一条维度轴算。
跨表只能靠名字 join工程台账里的乡镇名来自工程详表(人填),行政区划来自测绘边界(机器出)。撤乡设镇、更名、简称,两边就对不上,而且没有共同的编码
做法:先精确匹配,未命中的用曾用名/别名/同字前缀找候选,最后出一张命中率报告交人判——不静默丢,也不自动改。
源表登记的字段不一定对「工程规模」是有国标口径的(按总库容分级),但源表那一列是人填的,填错并不罕见。
做法:入库时按库容重算一遍并与登记值对账,冲突单独列出来给人判定,不自动覆盖
没有编码体系可依赖县名有「统计口径名」和「行政全称」两种写法(例如统计表写简称、台账写全称)。
做法:行政区划单独立一张 SSOT 表,其他表一律向它对齐,别名映射写在这一张表里,不在各处各自约定。

下面演示里的规模分级、库容系数、占比排除、字段并集、名称匹配,全部是当场算的,不是画的静态图。

统一之后,整个数据仓就是几张说得清结构的表。下面的行数是当场数出来的,不是写死的文案。

为什么统计表要留一个 JSON 列? 年报字段年年在变(今年多一个「跨流域调水」,明年公报汇总表又少两列)。 如果每来一版就 ALTER TABLE 加列,表会越长越宽,还得回头改所有下游查询。 这里把稳定的部分(县、年份、统计类型)做成三元唯一键建索引, 把易变的指标塞进一个 JSON 列,读的时候再决定有哪些列(schema-on-read)。 代价是不能直接对单个指标建索引——在这个数据量级(几千行)完全可以接受。

2 · 技术上怎么做的

存储按主题拆成若干个 SQLite 单文件库(工程台账 / 统计年报 / 行政区划 / 调查评价成果 / 空间切片)。单文件意味着免服务、可直接拷给同事、可进版本库看体积变化;跨库查询用 ATTACH DATABASE 在一个连接里 join,不搬数据。
半结构化统计表 = (县, 年份, 统计类型) 三元唯一键 + 一个 JSON 数据列。年报加字段不用改表结构;查询时按各年字段并集拼列,缺的画「—」。
幂等导入全部走 INSERT OR REPLACE + 唯一键:同一份源文件重跑多少次,结果都一样。DB 是派生物,源 Excel / PDF / shapefile 才是 SSOT——所以库本身不做备份,坏了重建即可。
口径纪律子项集合、单位、派生指标公式一律写成带注释的代码常量,不散落在各处口头约定。典型的一条:地表水 = 蓄+引+提+跨流域,所以这四项在算占比时必须排除,否则总和翻倍。
名称对齐行政区划单独立 SSOT 表(县 + 乡镇/街道,含曾用名与别名字段),其他表向它对齐。匹配失败不静默丢弃,产出命中率报告 + 候选建议,人工确认后再回写。
查询界面Web 端用 Datasette 直接挂库:字段中文别名、默认排序、facet 筛选器全写在一份 metadata 配置里,不写前端代码。同一批数据另配一组 CLI,输出直接就是 Markdown 表格,粘进报告即成稿——这才是设计人员真正每天用的入口。
空间数据shapefile 按县切成 GeoJSON 切片后入库,带 geometry 列,前端直接取切片渲染地图;切片文件比库新就自动重建,不用人记得刷新。

3 · 工程价值一句话

这套东西没有任何算法上的新意,它的全部价值在于把「口径」从人的脑子里搬进代码里。 在此之前,「这个县到底有几座中型水库」这种问题的答案取决于谁去数、数的哪一版表; 之后,它是一条可以复现、可以对账、可以被别人挑错的查询。 写报告时数字对不上的返工,比查数本身贵得多。

演示数据全部合成,全部计算在你的浏览器里完成。本页不向任何服务器发送数据,也不加载任何外部资源。