migration_drainage_waterlogging_point.sql 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. -- 易积水点台账表(KingbaseES, schema app_user)
  2. --
  3. -- 背景:旧表 app_user.psgw_waterlogging_point 混了「监测点」口径的字段,存在三类问题:
  4. -- 1) time(数据时间)、waterlogging_count(易积水点数量)属于运行数据/派生值,
  5. -- 不该落在基础档案表里;
  6. -- 2) waterlogging_points 存多节点坐标 JSON,但一个易积水点在地图上就是一个位置,
  7. -- 应直接落 WGS84 经纬度;
  8. -- 3) equipment_id 实际存的是「视频设备 ID(equipment_base.equipment_type_id=20)」,
  9. -- 易积水点关联的是摄像头,不是通用监测设备,字段名应表达真实语义。
  10. --
  11. -- 本脚本做四件事:
  12. -- 1. 建新表 app_user.drainage_waterlogging_point;
  13. -- 2. 对「已建过表」的库幂等补列(见步骤 1.1),两种执行顺序都能到位;
  14. -- 3. 登记字典「风险等级」(积水程度沿用已有字典 drainage_waterlogging_level);
  15. -- 4. 从旧表迁移数据(坐标取 waterlogging_points 的第一个点;解析失败置 NULL)。
  16. --
  17. -- 字段口径刻意保持精简(不做全量台账):
  18. -- 基本 point_code / point_name / district / location / longitude / latitude
  19. -- 积水 waterlogging_level / water_depth / water_volume / water_area
  20. -- 管理 risk_level / duty_unit / duty_person / duty_phone
  21. -- (后三项为名称快照,另有 duty_dept_id / duty_user_id 指向 sys_dept / sys_user,
  22. -- 由 migration_drainage_waterlogging_duty.sql 维护)
  23. -- 关联其他 camera_ids / remark / 审计字段 / del_flag
  24. --
  25. -- 说明:
  26. -- · 旧表的 equipment_id 直接搬进 camera_ids。若历史数据里曾混入过普通监测设备 ID,
  27. -- 迁移后需要人工核对(旧页面早期版本确实调用过通用设备关联)。
  28. -- · 幂等:建表/补列/索引/字典均可重复执行;数据迁移仅在「新表为空」时执行一次。
  29. --
  30. -- 前置:结束上一次失败执行遗留的 aborted 事务(事务外执行只会告警,不报错)
  31. ROLLBACK;
  32. BEGIN;
  33. -- =====================================================================
  34. -- 1. 建新表
  35. -- =====================================================================
  36. CREATE TABLE IF NOT EXISTS app_user.drainage_waterlogging_point (
  37. point_id varchar(64) NOT NULL,
  38. point_code varchar(64),
  39. point_name varchar(200) NOT NULL,
  40. district varchar(100),
  41. location varchar(500),
  42. longitude numeric(12, 8),
  43. latitude numeric(12, 8),
  44. waterlogging_level int2 DEFAULT 0,
  45. water_depth numeric(10, 2),
  46. water_volume numeric(14, 2),
  47. water_area numeric(14, 2),
  48. risk_level varchar(8),
  49. duty_unit varchar(200),
  50. duty_person varchar(64),
  51. duty_phone varchar(32),
  52. duty_dept_id bigint,
  53. duty_user_id bigint,
  54. camera_ids varchar(500),
  55. remark varchar(500),
  56. create_by varchar(64),
  57. create_time timestamp,
  58. update_by varchar(64),
  59. update_time timestamp,
  60. del_flag char(1) DEFAULT '0',
  61. CONSTRAINT pk_drainage_waterlogging_point PRIMARY KEY (point_id)
  62. );
  63. -- ---------------------------------------------------------------------
  64. -- 1.1 幂等补列:兼容「表已按旧版本建过」的库
  65. -- 逐列判断后 ALTER,已存在的列直接跳过。
  66. -- ---------------------------------------------------------------------
  67. DO $$
  68. DECLARE
  69. col record;
  70. BEGIN
  71. IF to_regclass('app_user.drainage_waterlogging_point') IS NULL THEN
  72. RETURN;
  73. END IF;
  74. FOR col IN
  75. SELECT * FROM (VALUES
  76. ('water_depth', 'numeric(10,2)'),
  77. ('water_area', 'numeric(14,2)'),
  78. ('risk_level', 'varchar(8)'),
  79. ('duty_unit', 'varchar(200)'),
  80. ('duty_person', 'varchar(64)'),
  81. ('duty_phone', 'varchar(32)'),
  82. ('duty_dept_id', 'bigint'),
  83. ('duty_user_id', 'bigint')
  84. ) AS x(name, type)
  85. LOOP
  86. IF NOT EXISTS (
  87. SELECT 1 FROM information_schema.columns
  88. WHERE table_schema = 'app_user'
  89. AND table_name = 'drainage_waterlogging_point'
  90. AND column_name = col.name
  91. ) THEN
  92. EXECUTE format('ALTER TABLE app_user.drainage_waterlogging_point ADD COLUMN %I %s',
  93. col.name, col.type);
  94. RAISE NOTICE '已补列:%', col.name;
  95. END IF;
  96. END LOOP;
  97. END $$;
  98. COMMENT ON TABLE app_user.drainage_waterlogging_point IS '易积水点台账';
  99. COMMENT ON COLUMN app_user.drainage_waterlogging_point.point_id IS '点位ID(主键)';
  100. COMMENT ON COLUMN app_user.drainage_waterlogging_point.point_code IS '点位编码';
  101. COMMENT ON COLUMN app_user.drainage_waterlogging_point.point_name IS '点位名称';
  102. COMMENT ON COLUMN app_user.drainage_waterlogging_point.district IS '所属区域';
  103. COMMENT ON COLUMN app_user.drainage_waterlogging_point.location IS '位置描述';
  104. COMMENT ON COLUMN app_user.drainage_waterlogging_point.longitude IS 'WGS84 经度';
  105. COMMENT ON COLUMN app_user.drainage_waterlogging_point.latitude IS 'WGS84 纬度';
  106. COMMENT ON COLUMN app_user.drainage_waterlogging_point.waterlogging_level IS '积水程度(字典 drainage_waterlogging_level:0未积水 1轻度 2中度 3严重)';
  107. COMMENT ON COLUMN app_user.drainage_waterlogging_point.water_depth IS '积水深度(cm)';
  108. COMMENT ON COLUMN app_user.drainage_waterlogging_point.water_volume IS '积水量(m³)';
  109. COMMENT ON COLUMN app_user.drainage_waterlogging_point.water_area IS '积水面积(m²)';
  110. COMMENT ON COLUMN app_user.drainage_waterlogging_point.risk_level IS '风险等级(字典 drainage_waterlogging_risk_level:0低风险 1中风险 2高风险)';
  111. COMMENT ON COLUMN app_user.drainage_waterlogging_point.duty_unit IS '责任单位(名称快照,对应 duty_dept_id)';
  112. COMMENT ON COLUMN app_user.drainage_waterlogging_point.duty_person IS '责任人(姓名快照,对应 duty_user_id)';
  113. COMMENT ON COLUMN app_user.drainage_waterlogging_point.duty_phone IS '联系电话(快照,选人时取 sys_user.phonenumber)';
  114. COMMENT ON COLUMN app_user.drainage_waterlogging_point.duty_dept_id IS '责任单位ID(sys_dept.dept_id)';
  115. COMMENT ON COLUMN app_user.drainage_waterlogging_point.duty_user_id IS '责任人ID(sys_user.user_id)';
  116. COMMENT ON COLUMN app_user.drainage_waterlogging_point.camera_ids IS '关联摄像头ID(equipment_base.equipment_id,多个用逗号分隔)';
  117. COMMENT ON COLUMN app_user.drainage_waterlogging_point.remark IS '备注';
  118. COMMENT ON COLUMN app_user.drainage_waterlogging_point.del_flag IS '删除标志(0正常 2删除)';
  119. CREATE INDEX IF NOT EXISTS idx_dwp_point_code ON app_user.drainage_waterlogging_point (point_code);
  120. CREATE INDEX IF NOT EXISTS idx_dwp_point_name ON app_user.drainage_waterlogging_point (point_name);
  121. CREATE INDEX IF NOT EXISTS idx_dwp_district ON app_user.drainage_waterlogging_point (district);
  122. CREATE INDEX IF NOT EXISTS idx_dwp_level ON app_user.drainage_waterlogging_point (waterlogging_level);
  123. CREATE INDEX IF NOT EXISTS idx_dwp_risk_level ON app_user.drainage_waterlogging_point (risk_level);
  124. -- =====================================================================
  125. -- 2. 字典:风险等级
  126. -- (积水程度沿用已有字典 drainage_waterlogging_level,本脚本不重复建)
  127. -- 注意:本库 sys_dict_data / sys_dict_type 是 MySQL 兼容 auto_increment,
  128. -- 自增计数器未随迁移数据推进,因此主键一律显式取 max+序号。
  129. -- =====================================================================
  130. INSERT INTO app_user.sys_dict_type
  131. (dict_id, dict_name, dict_type, status, create_by, create_time, remark)
  132. SELECT (SELECT COALESCE(MAX(dict_id), 0) FROM app_user.sys_dict_type) + 1,
  133. '易积水点风险等级', 'drainage_waterlogging_risk_level', '0', 'admin', CURRENT_TIMESTAMP,
  134. '风险等级:0低风险 1中风险 2高风险'
  135. WHERE NOT EXISTS (SELECT 1 FROM app_user.sys_dict_type WHERE dict_type = 'drainage_waterlogging_risk_level');
  136. UPDATE app_user.sys_dict_type
  137. SET dict_name = '易积水点风险等级',
  138. status = '0',
  139. update_by = 'admin',
  140. update_time = CURRENT_TIMESTAMP,
  141. remark = '风险等级:0低风险 1中风险 2高风险'
  142. WHERE dict_type = 'drainage_waterlogging_risk_level';
  143. DELETE FROM app_user.sys_dict_data WHERE dict_type = 'drainage_waterlogging_risk_level';
  144. INSERT INTO app_user.sys_dict_data
  145. (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class,
  146. is_default, status, create_by, create_time, remark)
  147. SELECT (SELECT COALESCE(MAX(dict_code), 0) FROM app_user.sys_dict_data) + v.rn,
  148. v.dict_sort, v.dict_label, v.dict_value, 'drainage_waterlogging_risk_level',
  149. '', v.list_class, v.is_default, '0', 'admin', CURRENT_TIMESTAMP, v.remark
  150. FROM (VALUES
  151. (1, 1, '低风险', '0', 'success', 'Y', '风险等级:低风险'),
  152. (2, 2, '中风险', '1', 'warning', 'N', '风险等级:中风险'),
  153. (3, 3, '高风险', '2', 'danger', 'N', '风险等级:高风险')
  154. ) AS v(rn, dict_sort, dict_label, dict_value, list_class, is_default, remark)
  155. ORDER BY v.rn;
  156. -- =====================================================================
  157. -- 3. 旧表数据迁移(仅当新表为空时执行一次)
  158. -- 可迁移的只有旧表真实存在的语义:名称/区域/积水量/积水程度/摄像头/坐标。
  159. -- =====================================================================
  160. DO $$
  161. DECLARE
  162. v_idx integer := 0;
  163. r record;
  164. v_lng numeric(12, 8);
  165. v_lat numeric(12, 8);
  166. BEGIN
  167. IF to_regclass('app_user.psgw_waterlogging_point') IS NULL THEN
  168. RAISE NOTICE '旧表 app_user.psgw_waterlogging_point 不存在,跳过数据迁移';
  169. RETURN;
  170. END IF;
  171. IF EXISTS (SELECT 1 FROM app_user.drainage_waterlogging_point) THEN
  172. RAISE NOTICE '新表 app_user.drainage_waterlogging_point 已有数据,跳过迁移(避免重复导入)';
  173. RETURN;
  174. END IF;
  175. FOR r IN SELECT * FROM app_user.psgw_waterlogging_point LOOP
  176. v_idx := v_idx + 1;
  177. v_lng := NULL;
  178. v_lat := NULL;
  179. BEGIN
  180. IF r.waterlogging_points IS NOT NULL AND r.waterlogging_points <> '' THEN
  181. v_lng := (regexp_match(r.waterlogging_points, '"lng"\s*:\s*(-?[0-9]+(\.[0-9]+)?)'))[1]::numeric(12, 8);
  182. v_lat := (regexp_match(r.waterlogging_points, '"lat"\s*:\s*(-?[0-9]+(\.[0-9]+)?)'))[1]::numeric(12, 8);
  183. END IF;
  184. EXCEPTION WHEN OTHERS THEN
  185. v_lng := NULL;
  186. v_lat := NULL;
  187. END;
  188. INSERT INTO app_user.drainage_waterlogging_point (
  189. point_id, point_code, point_name, district, location,
  190. longitude, latitude, waterlogging_level, water_volume, camera_ids,
  191. create_by, create_time, update_by, update_time, del_flag
  192. ) VALUES (
  193. r.id,
  194. 'JSD-' || lpad(v_idx::text, 4, '0'),
  195. COALESCE(NULLIF(trim(r.name), ''), '未命名易积水点'),
  196. r.area,
  197. NULL,
  198. v_lng,
  199. v_lat,
  200. COALESCE(r.waterlogging_level, 0),
  201. r.water_volume,
  202. r.equipment_id,
  203. 'admin', COALESCE(r.create_time, CURRENT_TIMESTAMP),
  204. 'admin', COALESCE(r.update_time, r.create_time, CURRENT_TIMESTAMP),
  205. '0'
  206. );
  207. END LOOP;
  208. RAISE NOTICE '旧表数据迁移完成,共迁移 % 条', v_idx;
  209. EXCEPTION WHEN OTHERS THEN
  210. RAISE NOTICE '旧表数据迁移跳过:%', SQLERRM;
  211. END $$;
  212. -- =====================================================================
  213. -- 4. 结果核验(可选,取消注释执行)
  214. -- =====================================================================
  215. -- 风险等级分布
  216. -- SELECT risk_level, count(*) FROM app_user.drainage_waterlogging_point
  217. -- WHERE del_flag = '0' GROUP BY risk_level;
  218. -- 风险等级字典(应返回 3 行)
  219. -- SELECT dict_value, dict_label, list_class FROM app_user.sys_dict_data
  220. -- WHERE dict_type = 'drainage_waterlogging_risk_level' ORDER BY dict_sort;
  221. COMMIT;