| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- -- =====================================================================
- -- 应急与指挥调度模块(dispatch)改造脚本 —— 存量数据搬迁
- -- 数据库:KingbaseES(PG 兼容模式),业务 schema = app_user
- --
- -- ⚠️ 使用前提:**只在有存量数据的环境执行**。
- -- 本脚本依赖旧表 / 旧列(dis_event.source、dis_event."level"、dis_event_report、
- -- dis_event_verify、dis_event_transfer_log、dis_event_track_log、
- -- dis_event_urge(_detail)、dis_event_plan、dis_plan_approval 等)。
- -- 全新库请勿执行 —— 所有块都用 to_regclass / information_schema 做了存在性判断,
- -- 缺失时自动跳过,但空跑一遍也没有意义。
- --
- -- 执行顺序:先 dispatch_refactor.sql(建表 + 加列 + 字典),再执行本脚本。
- --
- -- 幂等性:所有 INSERT 带 NOT EXISTS 去重;所有 UPDATE 带状态判断,可重复执行。
- -- 破坏性:无。本脚本不删除任何旧表、旧列、旧数据。
- --
- -- ⚠️ 执行注意(KingbaseES 客户端 · 事务挂起):
- -- 本脚本按「一 / 二 / 三 / 四」分成 4 个独立事务(每段 END $$; 后即 COMMIT;),
- -- 某段失败只回滚该段,前面已成功的段落保持落库。
- -- 但失败后当前连接仍处于 aborted 事务中,此后**所有**查询(包括只读 SELECT)
- -- 都会报「ERROR: 当前事务被终止, 事务块结束之前的查询被忽略」。
- -- 处理办法:先单独执行 ROLLBACK; 再排查失败语句;不要反复重跑。
- --
- -- ⚠️ 执行注意(客户端把注释行与语句拼在一起):
- -- 部分客户端在「选中运行」时会把紧邻的 `--` 注释行并入语句并吃掉一个减号,
- -- 报 `ERROR: 语法错误 在 "." 或附近的`。逐条执行时请**只选中 SQL 本体**。
- --
- -- ⚠️⚠️ 方言红线(本实例实测,务必遵守):**不要用 `||` 做字符串拼接**。
- -- 本实例的 KingbaseES 处于 MySQL 兼容语义,`||` 被解析为**逻辑或(boolean OR)**
- -- 而不是字符串连接符。实测:
- -- SELECT 'GJ' || '20261014' || '001'; -- 返回 boolean t (错)
- -- SELECT concat('GJ','20261014','001'); -- 返回 GJ20261014001(对)
- -- 后果:`SET grade_no = 'GJ' || to_char(...)` 会把 16 行全写成一个值 `'true'`,
- -- 第 2 行即撞唯一索引 uk_dis_event_grade_no,报
- -- ERROR: 重复键违反唯一约束 / DETAIL: 键值 "(grade_no)=(true)" 已经存在。
- -- 凡拼接一律改用 concat(a, b, c);需要定宽时配 lpad(CAST(x AS varchar), n, '0')。
- -- =====================================================================
- -- =====================================================================
- -- 零、前置体检(只读,先跑这里看一眼输出再往下)
- -- 作用:把「搬迁源还在不在」显式喊出来。
- -- 本脚本内部的搬迁块都用 to_regclass 做存在性判断,旧表/旧列不存在时**静默跳过**,
- -- 这是为了幂等;但代价是:若 drop 脚本被提前执行(顺序颠倒),
- -- 整个搬迁会一声不响地全部跳过,脚本却显示"成功"。
- -- 本段会在那种情况下直接抛 WARNING,避免数据悄悄丢。
- -- =====================================================================
- DO $$
- DECLARE
- n_old int;
- src text;
- BEGIN
- SELECT count(*), string_agg(t.n, ', ' ORDER BY t.n)
- INTO n_old, src
- FROM (VALUES ('dis_event_report'), ('dis_event_verify'), ('dis_event_transfer'),
- ('dis_event_transfer_log'), ('dis_event_track'), ('dis_event_track_log'),
- ('dis_event_urge'), ('dis_event_urge_detail'), ('dis_event_record'),
- ('dis_event_plan'), ('dis_plan_approval'), ('dis_plan_approval_step'),
- ('dis_plan_category')
- ) AS t(n)
- WHERE to_regclass(concat('app_user.', t.n)) IS NOT NULL;
- IF n_old = 0 THEN
- RAISE WARNING '搬迁源体检:未检测到任何旧表,本脚本将【不搬迁任何数据】(所有段都会跳过,但脚本仍显示成功)。';
- RAISE WARNING '可能原因:drop 脚本被提前执行,旧表已被删除 —— 被删的旧表正是本脚本唯一的数据来源。';
- RAISE WARNING '正确顺序是 建表 -> migrate(本脚本) -> 业务验证 -> drop;顺序颠倒会永久丢失存量数据。';
- ELSE
- RAISE NOTICE '搬迁源体检:检测到 % 张旧表(%),将执行搬迁。', n_old, src;
- END IF;
- IF to_regclass('app_user.dis_event_grade') IS NOT NULL
- AND EXISTS (SELECT 1 FROM information_schema.columns
- WHERE table_schema = 'app_user' AND table_name = 'dis_event_grade'
- AND column_name = 'category') THEN
- RAISE NOTICE 'detected: dis_event_grade 旧列 category / level 尚在,第 4.1 步可正常搬值。';
- ELSE
- RAISE NOTICE 'dis_event_grade 旧列 category / level 已不存在(或表不存在),第 4.1 步会跳过,event_category / event_level 将保持为空。';
- END IF;
- END $$;
- BEGIN;
- -- =====================================================================
- -- 一、dis_event 状态归一 + 旧列搬迁
- -- 旧 status(中文串):待受理/待核实/已核实/处置中/已解除/已关闭/不实事件
- -- 新 status(int2) :0 待核实 / 1 已核实 / 2 处置中 / 3 已解除 / 4 不实事件
- -- =====================================================================
- DO $$
- DECLARE
- has_source boolean;
- has_level boolean;
- has_category boolean;
- has_close_remark boolean;
- BEGIN
- SELECT EXISTS (SELECT 1 FROM information_schema.columns
- WHERE table_schema = 'app_user' AND table_name = 'dis_event' AND column_name = 'source')
- INTO has_source;
- SELECT EXISTS (SELECT 1 FROM information_schema.columns
- WHERE table_schema = 'app_user' AND table_name = 'dis_event' AND column_name = 'level')
- INTO has_level;
- SELECT EXISTS (SELECT 1 FROM information_schema.columns
- WHERE table_schema = 'app_user' AND table_name = 'dis_event' AND column_name = 'category')
- INTO has_category;
- SELECT EXISTS (SELECT 1 FROM information_schema.columns
- WHERE table_schema = 'app_user' AND table_name = 'dis_event' AND column_name = 'close_remark')
- INTO has_close_remark;
- -- 1.1 状态归一:只处理仍是中文串的行,重复执行不会二次改写
- UPDATE app_user.dis_event SET status = '0' WHERE status::text IN ('待受理', '待核实');
- UPDATE app_user.dis_event SET status = '1' WHERE status::text = '已核实';
- UPDATE app_user.dis_event SET status = '2' WHERE status::text = '处置中';
- UPDATE app_user.dis_event SET status = '3' WHERE status::text IN ('已解除', '已关闭');
- UPDATE app_user.dis_event SET status = '4' WHERE status::text = '不实事件';
- -- 兜底:任何未识别的历史状态归 0(待核实),避免后续类型转换失败
- UPDATE app_user.dis_event SET status = '0' WHERE status::text !~ '^[0-9]+$';
- -- 1.1b 列类型收敛:varchar → int2
- -- 必须在状态归一之后执行,否则中文值无法直接转型。
- -- 已是 int2 的库跳过。
- IF EXISTS (SELECT 1 FROM information_schema.columns
- WHERE table_schema = 'app_user' AND table_name = 'dis_event'
- AND column_name = 'status' AND data_type <> 'smallint') THEN
- EXECUTE 'ALTER TABLE app_user.dis_event ALTER COLUMN status TYPE int2 USING status::int2';
- END IF;
- -- 1.2 旧列 → 新列(仅当新列为空)
- IF has_source THEN
- EXECUTE 'UPDATE app_user.dis_event SET event_source = source WHERE event_source IS NULL AND source IS NOT NULL';
- EXECUTE $q$UPDATE app_user.dis_event SET event_source = '1' WHERE event_source = '巡查上报'$q$;
- EXECUTE $q$UPDATE app_user.dis_event SET event_source = '2' WHERE event_source = '呼叫中心'$q$;
- EXECUTE $q$UPDATE app_user.dis_event SET event_source = '3' WHERE event_source = '视频监控'$q$;
- EXECUTE $q$UPDATE app_user.dis_event SET event_source = '4' WHERE event_source = '上级下达'$q$;
- END IF;
- IF has_level THEN
- EXECUTE 'UPDATE app_user.dis_event SET event_level = "level" WHERE event_level IS NULL AND "level" IS NOT NULL';
- -- 旧 4 级 → 新 3 级口径映射;执行前请按业务确认,以下为默认映射
- EXECUTE $q$UPDATE app_user.dis_event SET event_level = '1' WHERE event_level IN ('特别重大', '重大', '一级', 'Ⅰ级', '紧急')$q$;
- EXECUTE $q$UPDATE app_user.dis_event SET event_level = '2' WHERE event_level IN ('较大', '二级', 'Ⅱ级')$q$;
- EXECUTE $q$UPDATE app_user.dis_event SET event_level = '3' WHERE event_level IN ('一般', '三级', '四级', 'Ⅲ级', 'Ⅳ级')$q$;
- END IF;
- IF has_category THEN
- EXECUTE 'UPDATE app_user.dis_event SET event_category = category WHERE event_category IS NULL AND category IS NOT NULL';
- EXECUTE $q$UPDATE app_user.dis_event SET event_category = '1' WHERE event_category = '管道泄漏'$q$;
- EXECUTE $q$UPDATE app_user.dis_event SET event_category = '2' WHERE event_category IN ('路面积水', '积水')$q$;
- EXECUTE $q$UPDATE app_user.dis_event SET event_category = '3' WHERE event_category IN ('设施损坏', '塌陷')$q$;
- EXECUTE $q$UPDATE app_user.dis_event SET event_category = '4' WHERE event_category IN ('管道堵塞', '堵塞')$q$;
- END IF;
- -- 1.3 解除说明兜底
- IF has_close_remark THEN
- EXECUTE 'UPDATE app_user.dis_event SET release_note = close_remark WHERE release_note IS NULL AND close_remark IS NOT NULL';
- END IF;
- -- 1.4 状态为终态但缺少时间列的兜底
- UPDATE app_user.dis_event SET dispose_time = COALESCE(dispose_time, report_time)
- WHERE status IN (2, 3) AND dispose_time IS NULL;
- UPDATE app_user.dis_event SET release_time = COALESCE(release_time, update_time, report_time)
- WHERE status = 3 AND release_time IS NULL;
- END $$;
- -- 分段提交:第一段成功即落库;后续段落失败时不会把本段一起回滚。
- COMMIT;
- BEGIN;
- -- =====================================================================
- -- 二、各子表 → dis_event_log
- -- 旧子表保留不动;待新结构验证通过后由 dispatch_refactor_drop.sql 处理。
- -- 对应关系:
- -- dis_event_report → oper_type 0 接报登记
- -- dis_event_verify → oper_type 1/2 初判核实 / 不实核销
- -- dis_event_transfer_log → oper_type 3/4 电话转接 / 上报报送
- -- dis_event_track_log → oper_type 6 处置跟踪
- -- dis_event_urge_detail → oper_type 8 工作催办
- -- 由状态轨迹推导 → oper_type 5 开始处置 / 7 事件解除
- -- =====================================================================
- DO $$
- BEGIN
- -- 2.1 接报登记
- IF to_regclass('app_user.dis_event_report') IS NOT NULL THEN
- INSERT INTO app_user.dis_event_log
- (event_id, event_no, oper_type, oper_desc, status_to, oper_time, oper_user_name)
- SELECT e.id, r.event_no, 0, '接报登记(历史数据迁移)', 0, r.report_time, r.reporter
- FROM app_user.dis_event_report r
- JOIN app_user.dis_event e ON e.event_no = r.event_no
- WHERE r.event_no IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM app_user.dis_event_log l
- WHERE l.event_no = r.event_no AND l.oper_type = 0);
- END IF;
- -- 2.2 初判核实 / 不实核销
- IF to_regclass('app_user.dis_event_verify') IS NOT NULL THEN
- INSERT INTO app_user.dis_event_log
- (event_id, event_no, oper_type, oper_desc, status_from, status_to, oper_time, oper_user_name)
- SELECT e.id, v.event_no,
- CASE WHEN v.is_real = '不实' THEN 2 ELSE 1 END,
- COALESCE(v.opinion, '初判核实(历史数据迁移)'),
- 0, CASE WHEN v.is_real = '不实' THEN 4 ELSE 1 END,
- v.verify_time, v.verifier
- FROM app_user.dis_event_verify v
- JOIN app_user.dis_event e ON e.event_no = v.event_no
- WHERE v.is_real IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM app_user.dis_event_log l
- WHERE l.event_no = v.event_no AND l.oper_type IN (1, 2));
- END IF;
- -- 2.3 电话转接 / 上报报送
- IF to_regclass('app_user.dis_event_transfer_log') IS NOT NULL THEN
- INSERT INTO app_user.dis_event_log
- (event_id, event_no, oper_type, oper_desc, targets, oper_time)
- SELECT e.id, l.event_no,
- CASE WHEN l.action_type = '报送' THEN 4 ELSE 3 END,
- COALESCE(l.content, '转接报送(历史数据迁移)'),
- l.action_target, l.action_time
- FROM app_user.dis_event_transfer_log l
- JOIN app_user.dis_event e ON e.event_no = l.event_no
- WHERE l.event_no IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM app_user.dis_event_log x
- WHERE x.event_no = l.event_no AND x.oper_type IN (3, 4)
- AND COALESCE(x.oper_time, TIMESTAMP '1970-01-01') = l.action_time);
- END IF;
- -- 2.4 处置跟踪
- IF to_regclass('app_user.dis_event_track_log') IS NOT NULL THEN
- INSERT INTO app_user.dis_event_log
- (event_id, event_no, oper_type, oper_desc, trend, need_upgrade, oper_time)
- SELECT e.id, l.event_no, 6,
- COALESCE(l.content, '处置跟踪(历史数据迁移)'),
- l.assessment,
- CASE WHEN l.need_upgrade = '是' THEN 1 ELSE 0 END,
- l.action_time
- FROM app_user.dis_event_track_log l
- JOIN app_user.dis_event e ON e.event_no = l.event_no
- WHERE l.event_no IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM app_user.dis_event_log x
- WHERE x.event_no = l.event_no AND x.oper_type = 6
- AND COALESCE(x.oper_time, TIMESTAMP '1970-01-01') = l.action_time);
- END IF;
- -- 2.5 工作催办
- IF to_regclass('app_user.dis_event_urge_detail') IS NOT NULL
- AND to_regclass('app_user.dis_event_urge') IS NOT NULL THEN
- INSERT INTO app_user.dis_event_log
- (event_id, event_no, oper_type, oper_desc, targets, receiver_dept, receiver_phone,
- method, urge_result, oper_time)
- SELECT e.id, d.event_no, 8,
- COALESCE(d.content, '工作催办(历史数据迁移)'),
- u.receiver, u.receiver_dept, u.receiver_phone,
- d.method,
- CASE d.result WHEN '已反馈' THEN '1' WHEN '未反馈' THEN '0' ELSE NULL END,
- d.urge_time
- FROM app_user.dis_event_urge_detail d
- JOIN app_user.dis_event_urge u ON u.id = d.urge_id
- JOIN app_user.dis_event e ON e.event_no = d.event_no
- WHERE d.event_no IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM app_user.dis_event_log x
- WHERE x.event_no = d.event_no AND x.oper_type = 8
- AND COALESCE(x.oper_time, TIMESTAMP '1970-01-01') = d.urge_time);
- END IF;
- -- 2.6 由状态轨迹推导「开始处置」
- -- 旧模型没有「开始处置时间」列,取最早一条处置跟踪日志的时间作代理;
- -- 无跟踪日志时回退到解除时间 / 接报时间。
- IF to_regclass('app_user.dis_event_track') IS NOT NULL
- AND to_regclass('app_user.dis_event_track_log') IS NOT NULL THEN
- INSERT INTO app_user.dis_event_log
- (event_id, event_no, oper_type, oper_desc, status_from, status_to, oper_time)
- SELECT e.id, e.event_no, 5, '开始处置(历史数据迁移)', 1, 2,
- COALESCE(m.first_track, e.release_time, e.report_time)
- FROM app_user.dis_event e
- LEFT JOIN (
- SELECT t.rel_event_id, MIN(l.action_time) AS first_track
- FROM app_user.dis_event_track t
- JOIN app_user.dis_event_track_log l ON l.track_id = t.id
- GROUP BY t.rel_event_id
- ) m ON m.rel_event_id = e.id
- WHERE e.status IN (2, 3)
- AND NOT EXISTS (SELECT 1 FROM app_user.dis_event_log x
- WHERE x.event_id = e.id AND x.oper_type = 5);
- END IF;
- -- 2.7 由状态轨迹推导「事件解除」
- INSERT INTO app_user.dis_event_log
- (event_id, event_no, oper_type, oper_desc, status_from, status_to, oper_time)
- SELECT e.id, e.event_no, 7,
- COALESCE(e.release_note, '事件解除(历史数据迁移)'), 2, 3, e.release_time
- FROM app_user.dis_event e
- WHERE e.status = 3 AND e.release_time IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM app_user.dis_event_log x
- WHERE x.event_id = e.id AND x.oper_type = 7);
- END $$;
- -- 分段提交:第二段成功即落库。
- COMMIT;
- BEGIN;
- -- =====================================================================
- -- 三、预案域:dis_event_plan + dis_plan_approval → dis_plan + dis_plan_version
- -- =====================================================================
- DO $$
- BEGIN
- IF to_regclass('app_user.dis_event_plan') IS NOT NULL THEN
- -- 3.1 主表搬迁;plan_no 用业务序号格式回填(YA + yyyyMMdd + 4 位补零序列)
- INSERT INTO app_user.dis_plan
- (plan_no, plan_name, plan_type, plan_level, compile_unit, publish_unit, publish_date,
- attach_name, attach_path, is_template, status, version, content, create_by, create_time)
- -- 拼接必须用 concat():本实例 `||` 是 boolean OR,详见文件头「方言红线」
- SELECT concat('YA', to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'),
- lpad(CAST(t.rn AS varchar), 4, '0')),
- t.plan_name, t.plan_type, t.plan_level, t.compile_unit, t.publish_unit, t.publish_date,
- t.attach_name, t.attach_path, 0, 0, t.version, t.plan_content, t.create_by, t.create_time
- FROM (SELECT p.*, row_number() OVER (ORDER BY p.id) AS rn
- FROM app_user.dis_event_plan p
- WHERE NOT EXISTS (SELECT 1 FROM app_user.dis_plan d WHERE d.plan_name = p.plan_name)) t;
- -- 3.2 已有正文且带版本号的历史预案,补一条「当前生效」版本快照
- INSERT INTO app_user.dis_plan_version
- (plan_id, plan_no, version, content, change_note, editor, edit_time, ver_status)
- SELECT d.id, d.plan_no, COALESCE(NULLIF(d.version, ''), 'v1.0'), d.content,
- '历史数据迁移', d.create_by, d.create_time, 1
- FROM app_user.dis_plan d
- WHERE d.status = 2
- AND NOT EXISTS (SELECT 1 FROM app_user.dis_plan_version v WHERE v.plan_id = d.id);
- END IF;
- -- 3.3 审批表状态合并:编辑中/审批中/终审中/已发布/待修正 → 0/1/1/2/3
- IF to_regclass('app_user.dis_plan_approval') IS NOT NULL THEN
- UPDATE app_user.dis_plan d
- SET status = CASE ap.status
- WHEN '已发布' THEN 2
- WHEN '审批中' THEN 1
- WHEN '终审中' THEN 1
- WHEN '待修正' THEN 3
- ELSE d.status END,
- approve_time = ap.approve_time,
- approve_note = COALESCE(d.approve_note, ap.audit_record),
- approve_result = CASE ap.status
- WHEN '已发布' THEN '通过'
- WHEN '待修正' THEN '不通过'
- ELSE d.approve_result END
- FROM app_user.dis_plan_approval ap
- WHERE d.plan_name = ap.plan_name
- AND d.status = 0;
- -- 3.4 审批轨迹补预案日志
- INSERT INTO app_user.dis_plan_log
- (plan_id, plan_no, oper_type, oper_desc, version, status_to, oper_user_name, oper_time)
- SELECT d.id, d.plan_no,
- CASE ap.status WHEN '已发布' THEN 2 WHEN '待修正' THEN 3 ELSE 1 END,
- COALESCE(ap.audit_record, '历史审批记录迁移'),
- ap.version,
- CASE ap.status WHEN '已发布' THEN 2 WHEN '待修正' THEN 3 ELSE 1 END,
- ap.reviewers, ap.approve_time
- FROM app_user.dis_plan_approval ap
- JOIN app_user.dis_plan d ON d.plan_name = ap.plan_name
- WHERE NOT EXISTS (SELECT 1 FROM app_user.dis_plan_log l WHERE l.plan_id = d.id);
- END IF;
- -- 3.5 预案等级旧 4 级口径 → 新 3 级口径(执行前请按业务确认)
- UPDATE app_user.dis_plan SET plan_level = '1'
- WHERE plan_level IN ('一级', 'Ⅰ级', '特别重大', '重大', '紧急');
- UPDATE app_user.dis_plan SET plan_level = '2'
- WHERE plan_level IN ('二级', 'Ⅱ级', '较大');
- UPDATE app_user.dis_plan SET plan_level = '3'
- WHERE plan_level IN ('三级', '四级', 'Ⅲ级', 'Ⅳ级', '一般');
- -- 3.6 预案类型中文 → 字典编码
- UPDATE app_user.dis_plan SET plan_type = '1' WHERE plan_type = '综合';
- UPDATE app_user.dis_plan SET plan_type = '2' WHERE plan_type = '专项';
- UPDATE app_user.dis_plan SET plan_type = '3' WHERE plan_type = '现场处置';
- END $$;
- -- 分段提交:第三段成功即落库。
- COMMIT;
- BEGIN;
- -- =====================================================================
- -- 四、事件分级:状态改数字 + 补业务编号
- -- =====================================================================
- DO $$
- BEGIN
- -- 4.1 先把旧列 category / level 搬到新列(必须早于下面的口径映射)
- IF EXISTS (SELECT 1 FROM information_schema.columns
- WHERE table_schema = 'app_user' AND table_name = 'dis_event_grade' AND column_name = 'category') THEN
- EXECUTE 'UPDATE app_user.dis_event_grade SET event_category = category WHERE event_category IS NULL AND category IS NOT NULL';
- END IF;
- IF EXISTS (SELECT 1 FROM information_schema.columns
- WHERE table_schema = 'app_user' AND table_name = 'dis_event_grade' AND column_name = 'level') THEN
- EXECUTE 'UPDATE app_user.dis_event_grade SET event_level = "level" WHERE event_level IS NULL AND "level" IS NOT NULL';
- END IF;
- -- 4.2 状态下沉:启用/停用 → 0/1
- UPDATE app_user.dis_event_grade SET status = '0' WHERE status::text IN ('启用', '正常');
- UPDATE app_user.dis_event_grade SET status = '1' WHERE status::text IN ('停用', '禁用');
- UPDATE app_user.dis_event_grade SET status = '0' WHERE status::text !~ '^[0-9]+$';
- IF EXISTS (SELECT 1 FROM information_schema.columns
- WHERE table_schema = 'app_user' AND table_name = 'dis_event_grade'
- AND column_name = 'status' AND data_type <> 'smallint') THEN
- EXECUTE 'ALTER TABLE app_user.dis_event_grade ALTER COLUMN status TYPE int2 USING status::int2';
- END IF;
- -- 4.3 等级口径:旧 4 级 → 新 3 级
- UPDATE app_user.dis_event_grade SET event_level = '1'
- WHERE event_level IN ('一级', 'Ⅰ级', '特别重大', '重大', '紧急');
- UPDATE app_user.dis_event_grade SET event_level = '2'
- WHERE event_level IN ('二级', 'Ⅱ级', '较大');
- UPDATE app_user.dis_event_grade SET event_level = '3'
- WHERE event_level IN ('三级', '四级', 'Ⅲ级', 'Ⅳ级', '一般');
- -- 4.4 类别口径
- UPDATE app_user.dis_event_grade SET event_category = '1'
- WHERE event_category IN ('管网泄漏', '管道泄漏');
- UPDATE app_user.dis_event_grade SET event_category = '2'
- WHERE event_category IN ('路面积水', '积水');
- UPDATE app_user.dis_event_grade SET event_category = '3'
- WHERE event_category IN ('设施损坏', '塌陷');
- UPDATE app_user.dis_event_grade SET event_category = '4'
- WHERE event_category IN ('管道堵塞', '堵塞');
- -- 4.5 业务编号回填:GJ + yyyyMMdd + 3 位序号(按 id 顺序)
- -- 防御一:只补 grade_no IS NULL 的行,可重复执行。
- -- 防御二:运行期取号(DispatchNumberSupport.nextGradeNo = GJ+yyyyMMdd+3位随机)
- -- 可能已经占用了同样的编号,这里逐个比对,撞号的候选值直接跳过
- -- (该行保持 NULL,由页面人工补号),避免 uk_dis_event_grade_no 报重复键。
- -- 注意:CURRENT_TIMESTAMP 在单个事务内是常量,同批回填的日期段一致。
- -- 注意:拼接必须用 concat()。本实例 `||` 被解析为 boolean OR,
- -- 写成 'GJ' || to_char(...) || lpad(...) 会让整列都变成 'true'(详见文件头)。
- UPDATE app_user.dis_event_grade g
- SET grade_no = c.new_no
- FROM (SELECT t.id,
- concat('GJ', to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'),
- lpad(CAST(t.rn AS varchar), 3, '0')) AS new_no
- FROM (SELECT id, row_number() OVER (ORDER BY id) AS rn
- FROM app_user.dis_event_grade
- WHERE grade_no IS NULL) t) c
- WHERE g.id = c.id
- AND NOT EXISTS (SELECT 1 FROM app_user.dis_event_grade x
- WHERE x.grade_no = c.new_no);
- END $$;
- COMMIT;
- -- =====================================================================
- -- 五、迁移结果自检
- -- =====================================================================
- -- 1) 事件状态分布:只应是 0~4
- -- SELECT status, count(*) FROM app_user.dis_event GROUP BY status ORDER BY status;
- -- 2) 事件主表编号唯一性
- -- SELECT event_no, count(*) FROM app_user.dis_event GROUP BY event_no HAVING count(*) > 1;
- -- 3) 日志迁移覆盖率:有事件但无日志的异常数据
- -- SELECT e.id, e.event_no FROM app_user.dis_event e
- -- WHERE NOT EXISTS (SELECT 1 FROM app_user.dis_event_log l WHERE l.event_id = e.id);
- -- 4) 各操作类型日志条数
- -- SELECT oper_type, count(*) FROM app_user.dis_event_log GROUP BY oper_type ORDER BY oper_type;
- -- 5) 预案:有主表但无版本快照的已通过预案
- -- SELECT d.id, d.plan_no, d.status FROM app_user.dis_plan d
- -- WHERE d.status = 2 AND NOT EXISTS (SELECT 1 FROM app_user.dis_plan_version v WHERE v.plan_id = d.id);
- -- 6) 分级标准编号回填情况
- -- SELECT count(*) AS total, count(grade_no) AS with_no FROM app_user.dis_event_grade;
|