基于SQL数据库的废弃物管理系统风险因子计算优化求助
优化废弃物管理系统的风险因子计算SQL视图
我正在开发一套废弃物管理系统,需要依据工业污水、生活污水等不同废弃物的风险因子优先安排处置动作。系统采用SQL数据库存储污染对象的年龄、位置、污染类型等信息,但在创建RiskReport视图计算风险因子时,结果不符合预期,尤其是无法正确纳入水体邻近标准。我需要优化SQL代码,让视图输出包含nearWaterRisk、nearCityRisk、distanceToWater、distanceToCity字段的结果,且水体风险优先级高于城区风险。
数据库架构
-- Contaminated objects table CREATE TABLE ContaminatedObject ( id INTEGER PRIMARY KEY, name TEXT, age INTEGER, position POINT, extension REAL ); -- Sewage contamination table CREATE TABLE SewageContamination ( id INTEGER PRIMARY KEY, contaminatedObjectId INTEGER, sewageType TEXT, sewageVolume FLOAT, owner TEXT, FOREIGN KEY (contaminatedObjectId) REFERENCES ContaminatedObject(id) ); -- Industrial contamination table CREATE TABLE IndustrialContamination ( id INTEGER PRIMARY KEY, contaminatedObjectId INTEGER, industrialWasteType TEXT, industrialWasteVolume TEXT, owner TEXT, FOREIGN KEY (contaminatedObjectId) REFERENCES ContaminatedObject(id) ); -- Issues table CREATE TABLE Issue ( id INTEGER PRIMARY KEY, objectId INTEGER, issueType TEXT, date TIMESTAMP, documentation TEXT, FOREIGN KEY (objectId) REFERENCES ContaminatedObject(id) ); -- Historical records table for documentation CREATE TABLE HistoricalRecord ( id INTEGER PRIMARY KEY, objectId INTEGER, action TEXT, timestamp TIMESTAMP, FOREIGN KEY (objectId) REFERENCES ContaminatedObject(id) ); -- City bodies table CREATE TABLE City ( id INTEGER PRIMARY KEY, cityName TEXT, position POINT ); -- Water bodies table CREATE TABLE WaterBody ( id INTEGER PRIMARY KEY, waterBodyname TEXT, position POINT );
样本数据
-- Insert sample data into the ContaminatedObject table INSERT INTO ContaminatedObject (name, age, position, extension) VALUES ('Object 1', 20, ST_GeomFromText('POINT(10 20)'), 50.5), ('Object 2', 30, ST_GeomFromText('POINT(30 40)'), 60.7), ('Object 3', 25, ST_GeomFromText('POINT(50 60)'), 70.2); -- Insert sample data into the SewageContamination table INSERT INTO SewageContamination (contaminatedObjectId, sewageType, sewageVolume, owner) VALUES (1, 'chromium', 100.5, 'Owner A'), (2, 'arsenic', 200.7, 'Owner B'); -- Insert sample data into the IndustrialContamination table INSERT INTO IndustrialContamination (contaminatedObjectId, industrialWasteType, industrialWasteVolume, owner) VALUES (1, 'arsenic', 145, 'Owner C'), (3, 'arsenic', 105, 'Owner D'); -- Insert sample data into the City table INSERT INTO City (cityName, position) VALUES ('City 1', ST_GeomFromText('POINT(15 25)')); -- Insert sample data into the WaterBody table INSERT INTO WaterBody (waterBodyname, position) VALUES ('Lake 1', ST_GeomFromText('POINT(20 30)')), ('Lake 2', ST_GeomFromText('POINT(40 50)'));
动作优先级判定标准
- 年限标准:使用年限超过40年的设施优先检查
- 水体邻近标准:距离水体250米以内的设施因污染水体风险高需优先处理
- 分类标准:需考虑污染类型、污染量、与城区的距离等因素
优化后的RiskReport视图实现
核心思路
- 计算每个污染对象到最近水体/城区的实际地理距离
- 基于距离阈值生成
nearWaterRisk和nearCityRisk标识 - 整合年限、污染类型、污染量等因子计算综合风险得分,赋予水体风险更高权重
- 按水体风险优先、综合得分降序排序,满足处置优先级要求
视图SQL代码(兼容PostGIS/MySQL)
CREATE OR REPLACE VIEW RiskReport AS WITH ObjectDistances AS ( SELECT co.id AS objectId, co.name, co.age, co.position, -- 计算到最近水体的距离(PostGIS用ST_Distance,MySQL替换为ST_Distance_Sphere) MIN(ST_Distance(co.position, wb.position)) AS distanceToWater, -- 计算到最近城区的距离 MIN(ST_Distance(co.position, c.position)) AS distanceToCity FROM ContaminatedObject co CROSS JOIN WaterBody wb CROSS JOIN City c GROUP BY co.id, co.name, co.age, co.position ), ContaminationDetails AS ( SELECT co.id AS objectId, -- 合并并去重污水污染类型 GROUP_CONCAT(DISTINCT sc.sewageType) AS sewageTypes, -- 累计污水总量,空值补0 COALESCE(SUM(sc.sewageVolume), 0) AS totalSewageVolume, -- 合并并去重工业污染类型 GROUP_CONCAT(DISTINCT ic.industrialWasteType) AS industrialWasteTypes, -- 累计工业废弃物总量,空值补0并转换为数值类型 COALESCE(SUM(CAST(ic.industrialWasteVolume AS FLOAT)), 0) AS totalIndustrialWasteVolume FROM ContaminatedObject co LEFT JOIN SewageContamination sc ON co.id = sc.contaminatedObjectId LEFT JOIN IndustrialContamination ic ON co.id = ic.contaminatedObjectId GROUP BY co.id ) SELECT od.objectId, od.name, od.age, -- 保留原始距离值,保留2位小数 ROUND(od.distanceToWater, 2) AS distanceToWater, ROUND(od.distanceToCity, 2) AS distanceToCity, -- 水体邻近风险:250米以内标记为高风险(1=高风险,0=低风险) CASE WHEN od.distanceToWater <= 250 THEN 1 ELSE 0 END AS nearWaterRisk, -- 城区邻近风险:示例阈值设为500米,可根据业务调整 CASE WHEN od.distanceToCity <= 500 THEN 1 ELSE 0 END AS nearCityRisk, -- 综合风险得分:权重向水体风险倾斜 ( -- 年限风险:超过40年加20分 CASE WHEN od.age > 40 THEN 20 ELSE 0 END -- 水体风险:高风险加60分(最高权重) + (od.nearWaterRisk * 60) -- 城区风险:高风险加20分 + (od.nearCityRisk * 20) -- 污染量风险:每100单位加10分 + (ROUND((cd.totalSewageVolume + cd.totalIndustrialWasteVolume) / 100) * 10) -- 高危污染物(砷、铬)加15分,可扩展更多类型 + CASE WHEN cd.sewageTypes LIKE '%arsenic%' OR cd.sewageTypes LIKE '%chromium%' OR cd.industrialWasteTypes LIKE '%arsenic%' OR cd.industrialWasteTypes LIKE '%chromium%' THEN 15 ELSE 0 END ) AS totalRiskScore FROM ObjectDistances od JOIN ContaminationDetails cd ON od.objectId = cd.objectId -- 排序规则:水体风险优先,再按综合得分降序 ORDER BY nearWaterRisk DESC, totalRiskScore DESC;
关键细节说明
- 距离计算适配:MySQL环境需将
ST_Distance替换为ST_Distance_Sphere,该函数返回以米为单位的球面距离,符合实际地理空间计算需求 - 空值处理:用
COALESCE确保无污染记录的对象不会出现NULL值,避免计算错误 - 权重调整:可根据业务需求修改得分公式中的权重(比如调整水体风险的分值占比)
- 高危污染物扩展:可在
CASE语句中添加更多高危污染物类型,适配不同场景
查询结果示例
执行SELECT * FROM RiskReport;将得到包含所有目标字段的结果,且水体高风险对象会排在最前面,完全符合优先级要求。
内容的提问来源于stack exchange,提问作者Apoas
相关产品推荐
相关产品推荐

