| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- -- 排水分区「积水等级」字典(KingbaseES)
- -- 用途:排水分区基础数据管理(psgw_drainage_partition.level)的积水等级改为字典驱动,
- -- 下拉框、列表标签配色、详情展示统一读取 sys_dict_data。
- -- 口径:与易积水点(WaterloggingPoint.waterlogging_level)保持一致
- -- 0-未积水 / 1-轻度积水 / 2-中度积水 / 3-严重积水。
- -- 说明:只维护字典定义,不改表结构、不改业务数据;脚本幂等,可重复执行。
- --
- -- =====================================================================
- -- 为什么本脚本要「显式指定主键」
- -- ---------------------------------------------------------------------
- -- 本库由 MySQL 迁移至 Kingbase,sys_dict_data / sys_dict_type 建表沿用了 MySQL 的
- -- auto_increment(KES 的 MySQL 兼容自增,不是 PG 的 serial/identity)。迁数据时是带显式
- -- 主键写入的,自增计数器没有跟着推进,于是「INSERT 不写主键」会发出一个已被占用的号:
- -- ERROR: 重复键违反唯一约束 "sys_dict_data_pkey"
- -- DETAIL: 键值 "dict_code"=(415) 已经存在
- -- 且该列不是 identity 列,pg_get_serial_sequence / pg_depend 都拿不到序列,
- -- ALTER COLUMN ... RESTART WITH 也会报「不是标识列」。
- --
- -- 因此处理方式是:
- -- ① INSERT 一律写成 max(主键) + n,显式指定,彻底绕开自增计数器;
- -- ② 插入完再把能找到的序列 setval 到最新 max(步骤 3),让后续新增不受影响;
- -- 若确实没有关联序列(纯 auto_increment),步骤 3 只提示、不报错。
- -- =====================================================================
- --
- -- 前置(必须先执行):结束上一次失败执行遗留的 aborted 事务
- -- 上一次语句报错后,PG/KES 会把该事务标记为已失败,此时同一连接上后续任何语句都只返回
- -- 「当前事务被终止,事务块结束之前的查询被忽略」,必须先回滚才能继续。
- -- 注意:本句会回滚该连接上所有未提交事务;若你有别的未提交手工操作,请先单独提交再跑本脚本。
- ROLLBACK;
- BEGIN;
- -- 1. 字典类型(幂等登记;dict_id 显式取 max+1)
- INSERT INTO app_user.sys_dict_type
- (dict_id, dict_name, dict_type, status, create_by, create_time, remark)
- SELECT (SELECT COALESCE(MAX(dict_id), 0) FROM app_user.sys_dict_type) + 1,
- '积水等级', 'drainage_waterlogging_level', '0', 'admin', CURRENT_TIMESTAMP,
- '积水等级:0未积水 1轻度积水 2中度积水 3严重积水'
- WHERE NOT EXISTS (SELECT 1 FROM app_user.sys_dict_type WHERE dict_type = 'drainage_waterlogging_level');
- UPDATE app_user.sys_dict_type
- SET dict_name = '积水等级',
- status = '0',
- update_by = 'admin',
- update_time = CURRENT_TIMESTAMP,
- remark = '积水等级:0未积水 1轻度积水 2中度积水 3严重积水'
- WHERE dict_type = 'drainage_waterlogging_level';
- -- 2. 字典数据(幂等重写;dict_code 显式取 max+序号;list_class 决定列表标签配色)
- DELETE FROM app_user.sys_dict_data WHERE dict_type = 'drainage_waterlogging_level';
- INSERT INTO app_user.sys_dict_data
- (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class,
- is_default, status, create_by, create_time, remark)
- SELECT (SELECT COALESCE(MAX(dict_code), 0) FROM app_user.sys_dict_data) + v.rn,
- v.dict_sort, v.dict_label, v.dict_value, 'drainage_waterlogging_level',
- '', v.list_class, v.is_default, '0', 'admin', CURRENT_TIMESTAMP, v.remark
- FROM (VALUES
- (1, 1, '未积水', '0', 'success', 'Y', '积水等级:未积水'),
- (2, 2, '轻度积水', '1', 'primary', 'N', '积水等级:轻度积水'),
- (3, 3, '中度积水', '2', 'warning', 'N', '积水等级:中度积水'),
- (4, 4, '严重积水', '3', 'danger', 'N', '积水等级:严重积水')
- ) AS v(rn, dict_sort, dict_label, dict_value, list_class, is_default, remark)
- ORDER BY v.rn;
- -- 3. 自增计数器校准(放在插入之后:此时 max 已含新插入的 4 行)
- -- 三种方式依次尝试,任一成功即可;都不成功只提示,不影响本脚本已插入的数据。
- -- 方式一 pg_get_serial_sequence(serial / identity)
- -- 方式二 从列默认值里解析 nextval('...')(KES 常见形态)
- -- 方式三 pg_depend 关联序列(兜底)
- DO $$
- DECLARE
- t record;
- v_seq text;
- v_max bigint;
- v_default text;
- BEGIN
- FOR t IN
- SELECT * FROM (VALUES ('sys_dict_data', 'dict_code'),
- ('sys_dict_type', 'dict_id')) AS x(tbl, col)
- LOOP
- v_seq := NULL;
- v_default := NULL;
- -- 方式一
- BEGIN
- v_seq := pg_get_serial_sequence(format('app_user.%I', t.tbl), t.col);
- EXCEPTION WHEN OTHERS THEN
- v_seq := NULL;
- END;
- -- 方式二:解析列默认值里的 nextval('xxx')
- IF v_seq IS NULL THEN
- BEGIN
- SELECT pg_get_expr(ad.adbin, ad.adrelid) INTO v_default
- FROM pg_attribute a
- JOIN pg_attrdef ad ON ad.adrelid = a.attrelid AND ad.adnum = a.attnum
- WHERE a.attrelid = format('app_user.%I', t.tbl)::regclass
- AND a.attname::text = t.col
- AND a.attnum > 0
- AND NOT a.attisdropped;
- EXCEPTION WHEN OTHERS THEN
- v_default := NULL;
- END;
- IF v_default LIKE '%nextval%' THEN
- v_seq := substring(v_default from 'nextval\(''([^'']+)''');
- END IF;
- END IF;
- -- 方式三
- IF v_seq IS NULL THEN
- BEGIN
- SELECT d.objid::regclass::text INTO v_seq
- FROM pg_depend d
- JOIN pg_attribute a ON a.attrelid = d.refobjid AND a.attnum = d.refobjsubid
- JOIN pg_class sc ON sc.oid = d.objid AND sc.relkind = 'S'
- WHERE d.refobjid = format('app_user.%I', t.tbl)::regclass
- AND a.attname::text = t.col
- AND d.deptype IN ('a', 'i')
- LIMIT 1;
- EXCEPTION WHEN OTHERS THEN
- v_seq := NULL;
- END;
- END IF;
- IF v_seq IS NULL THEN
- RAISE NOTICE '%.% 没有关联序列(应为 MySQL 兼容 auto_increment),跳过校准。本次数据已显式指定主键插入,不影响本脚本;但后续在该表手工新增行仍可能撞主键。',
- t.tbl, t.col;
- CONTINUE;
- END IF;
- EXECUTE format('SELECT COALESCE(max(%I), 0) FROM app_user.%I', t.col, t.tbl) INTO v_max;
- BEGIN
- PERFORM setval(v_seq::regclass, GREATEST(v_max, 1), true);
- RAISE NOTICE '%.% 自增序列已校准: % (max=%, next=%)', t.tbl, t.col, v_seq, v_max, v_max + 1;
- EXCEPTION WHEN OTHERS THEN
- RAISE NOTICE '%.% 序列校准失败: %,跳过', t.tbl, t.col, SQLERRM;
- END;
- END LOOP;
- END $$;
- -- 4. 存量数据体检(只查不改):level 为空或不在 0-3 的记录
- -- SELECT id, name, "level" FROM app_user.psgw_drainage_partition
- -- WHERE "level" IS NULL OR "level" NOT IN (0, 1, 2, 3);
- -- 5. 结果核验(可选,取消注释执行):应返回 4 行,dict_value 依次 0~3
- -- SELECT dict_value, dict_label, list_class FROM app_user.sys_dict_data
- -- WHERE dict_type = 'drainage_waterlogging_level' ORDER BY dict_sort;
- COMMIT;
|