2. 钻孔数据库总体设计
钻孔数据库是柱状图自动出图的“数据底座”。柱状图上的每一根分层线、每一个取样符号、每一段水位标注,最终都要能追溯到数据库中的某一条记录。因此总体设计要解决四个问题:用什么数据库、建哪些表、字段怎么命名、表与表之间靠什么关联。设计得当,后续出图脚本只需按固定视图取数;设计不当,就会出现“图能画出来但数据对不上”的返工。
一、数据库选型:以单机文件型为主,兼顾协同
勘察项目的数据规模通常不大:一个中型工民建项目约几十到几百个钻孔,每个钻孔几十条分层记录、若干取样与测试记录,总量在万级到十万级行。这种量级下,选型的关键不是并发性能,而是部署简单、便于携带、易于备份和交付。推荐以 SQLite 作为单项目主库:单文件存储,随项目文件夹一起归档,出图脚本用 Python 的 sqlite3 或 SQLAlchemy 直接读取,无需安装服务端。对于需要多人同时录入的院级生产环境,可选用 PostgreSQL 或 MySQL,把 SQLite 作为外业离线采集库,回到内业后按统一表结构导入中心库。若单位已有 GIS 平台,也可将钻孔表挂接到空间库中,用孔口坐标直接生成孔位图,但柱状图出图仍建议走独立的关系表,避免空间库的字段约束干扰录入。
选型时还要确认字符集与数值精度:地层名称、岩性描述含中文,统一用 UTF-8;孔口高程、分层深度用定点小数而非浮点,避免 0.1+0.2 这类误差在累计深度上放大,导致分层线与取样深度错位。
二、核心表结构:一孔一主表,多事一子表
按“钻孔—事件”的思路拆表:钻孔本身的信息放主表,一个钻孔对应一条记录;分层、取样、原位测试、水位都是“在某深度发生的事件”,各自建子表,通过孔号关联。核心表建议如下:
- 钻孔基本信息表 borehole:孔号、工程编号、孔口坐标 X/Y、孔口高程、终孔深度、钻孔类型(取土孔/标贯孔/鉴别孔)、施工日期、钻机型号、水位初见深度等。
- 地层分层表 stratum:孔号、层序号、层底深度、层顶深度(可由上一层推出,但建议冗余存储便于校验)、岩土名称、岩性描述、地层代号、颜色、状态、密实度/稠度。
- 取样表 sample:孔号、样品编号、取样顶深度、取样底深度、样品类型(原状/扰动/岩样/水样)、取样方式、试验项目。
- 原位测试表 insitu_test:孔号、试验类型(标准贯入/动力触探/静力触探/波速)、试验深度、击数或比贯入阻力、试验日期。
- 水位表 water_level:孔号、观测日期、初见水位、稳定水位、观测方式。
这里有一个容易忽略的细节:深度统一用“自孔口向下为正”的深度值,而不是标高。出图时再按“孔口高程 − 深度”换算成标高绘制,这样外业记录与内业成图参照系一致,避免正负号混乱。分层表同时存层顶、层底,是为了在导入时用“上一层底 = 下一层顶”做连续性校验,一旦出现空段或重叠立即报警。
三、字段命名规范:可读、可校验、可扩展
字段命名建议采用“小写下划线 + 业务前缀”的风格,主键统一为 id,外键统一为 bh_id(钻孔主键)而非孔号字符串,孔号另设唯一索引 bh_code。深度类字段统一以 _depth 结尾,高程类以 _elev 结尾,日期类以 _date 结尾,这样出图脚本按后缀就能批量识别深度字段。数值字段明确单位并在字段名或注释中标注,例如 spt_blow 表示标准贯入击数,water_depth 单位为米。枚举值用短代码存储(如样品类型 U 原状、D 扰动、R 岩样),另建字典表维护中文显示名,保证图面标注与库内编码解耦。
四、关联关系与出图取数
五张表以 bh_id 为纽带形成一对多关系:一个钻孔对应多条分层、多个样品、多组测试、多次水位观测。出图时按孔号取主表一条记录,再分别按深度排序取各子表记录,即可驱动柱状图的分层栏、取样栏、测试栏和水位线。为保证图面顺序稳定,所有子表查询必须显式 ORDER BY 深度字段。
上图把“一主四子”的结构和取数方向画在一起:主表提供孔口高程与终孔深度,决定图幅纵向范围;四张子表分别对应柱状图的分层栏、取样栏、测试栏和水位线。实际建库时,建议再建一个视图 v_borehole_profile,把主表与各子表按孔号拼成宽表,出图脚本只读视图,表结构后续调整时不必改动绘图代码。
最后给出一个可直接参考的建表片段(SQLite 语法,示例字段,实际项目按需增删):
CREATE TABLE borehole (
id INTEGER PRIMARY KEY,
bh_code TEXT NOT NULL UNIQUE,
x_coord REAL, y_coord REAL,
collar_elev REAL NOT NULL,
final_depth REAL NOT NULL,
hole_type TEXT,
drill_date TEXT,
water_first_depth REAL
);
CREATE TABLE stratum (
id INTEGER PRIMARY KEY,
bh_id INTEGER NOT NULL REFERENCES borehole(id),
layer_no INTEGER NOT NULL,
top_depth REAL NOT NULL,
bottom_depth REAL NOT NULL,
soil_name TEXT NOT NULL,
stratum_code TEXT,
description TEXT,
UNIQUE(bh_id, layer_no)
);
CREATE TABLE sample (
id INTEGER PRIMARY KEY,
bh_id INTEGER NOT NULL REFERENCES borehole(id),
sample_code TEXT NOT NULL,
top_depth REAL NOT NULL,
bottom_depth REAL NOT NULL,
sample_type TEXT,
test_item TEXT
);
CREATE TABLE insitu_test (
id INTEGER PRIMARY KEY,
bh_id INTEGER NOT NULL REFERENCES borehole(id),
test_type TEXT NOT NULL,
test_depth REAL NOT NULL,
spt_blow INTEGER,
test_date TEXT
);
CREATE TABLE water_level (
id INTEGER PRIMARY KEY,
bh_id INTEGER NOT NULL REFERENCES borehole(id),
obs_date TEXT,
first_depth REAL,
stable_depth REAL,
obs_method TEXT
);
建好表后,用一条简单查询即可验证关联是否通畅:按孔号统计各子表记录数,若某孔分层数为 0 或层底深度小于终孔深度,说明录入缺失,应在出图前补录。数据库设计阶段多花半天把表结构、命名和约束定死,后续柱状图自动出图才能稳定复现,而不是每次出图都靠人工核对。