-- ===================================================================== -- dispatch_fix_all_identity.sql -- 一次性对齐 app_user 下所有 dis_* 表的主键自增序列 -- --------------------------------------------------------------------- -- 背景:调度模块各表(dis_event / dis_event_log / dis_plan / dis_plan_version / -- dis_event_grade / dis_event_assess / dis_plan_log / dis_plan_library / -- dis_plan_match_record 等)由 MySQL 迁移至 Kingbase,迁移数据时带显式 id -- 插入,GENERATED BY DEFAULT AS IDENTITY 的序列不会自动推进;此后不带 -- id 的 INSERT 会从序列起点发号(如发 0),撞已存在行,报主键冲突。 -- 修复:遍历 app_user 下所有 dis_% 表,把 id 列关联的序列 setval 到 max(id) -- (setval(seq, max, true) → 下一个发号 = max+1)。幂等可重复执行。 -- 执行方式:KingbaseES 客户端。逐段执行;某段失败先 ROLLBACK 再继续下一段。 -- ===================================================================== -- --------------------------------------------------------------------- -- 步骤 0(可选):先看各表现状——max(id) 与序列名,便于核对 -- --------------------------------------------------------------------- SELECT c.relname AS 表名, (SELECT COALESCE(max(id), 0) FROM app_user.dis_event) AS 说明_另查, d.objid::regclass::text AS 关联序列 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace LEFT JOIN pg_depend d ON d.refobjid = c.oid AND d.classid = 'pg_class'::regclass AND d.deptype IN ('a', 'i') LEFT JOIN pg_attribute a ON a.attrelid = d.refobjid AND a.attnum = d.refobjsubid AND a.attname = 'id' WHERE n.nspname = 'app_user' AND c.relname LIKE 'dis_%' AND c.relkind = 'r'; -- --------------------------------------------------------------------- -- 步骤 1(首选):自动遍历所有 dis_% 表,校准 id 序列 -- 执行成功会逐表 NOTICE 输出「表名 -> 序列名 (next=...)」 -- --------------------------------------------------------------------- DO $$ DECLARE t record; seqname text; maxid bigint; BEGIN FOR t IN SELECT c.relname AS table_name FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = 'app_user' AND c.relname LIKE 'dis\_%' ESCAPE '\' AND c.relkind = 'r' LOOP EXECUTE format('SELECT COALESCE(max(id), 0) FROM app_user.%I', t.table_name) INTO maxid; -- 找 id 列关联的序列(serial=deptype a / identity=deptype i) SELECT d.objid::regclass::text INTO seqname 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' JOIN pg_namespace sn ON sn.oid = sc.relnamespace AND sn.nspname = 'app_user' WHERE d.refobjid = format('app_user.%I', t.table_name)::regclass AND a.attname = 'id' AND d.classid = 'pg_class'::regclass AND d.deptype IN ('a', 'i') LIMIT 1; IF seqname IS NOT NULL THEN EXECUTE format('SELECT setval(%L::regclass, %s, true)', seqname, GREATEST(maxid, 1)); RAISE NOTICE '% -> % (next=%)', t.table_name, seqname, maxid + 1; ELSE RAISE NOTICE '% -> 未找到关联序列,请用步骤 2 手工处理', t.table_name; END IF; END LOOP; END $$; -- --------------------------------------------------------------------- -- 步骤 2(保底):步骤 1 中提示「未找到关联序列」的表,手工对齐 -- 先查该表 max(id),把下面的 替换为 max(id)(RESTART WITH 生效值即下一个发号): -- ALTER TABLE app_user.表名 ALTER COLUMN id RESTART WITH ; -- -- 例(编号仅为示例,以步骤 0 查到的 max(id) 为准): -- ALTER TABLE app_user.dis_event ALTER COLUMN id RESTART WITH 100; -- ALTER TABLE app_user.dis_event_log ALTER COLUMN id RESTART WITH 300; -- ALTER TABLE app_user.dis_event_assess ALTER COLUMN id RESTART WITH 10; -- --------------------------------------------------------------------- -- --------------------------------------------------------------------- -- 步骤 3:核验——逐表 nextval 应等于 max(id) + 1(多表循环核验可重复步骤 0) -- 示例: -- SELECT COALESCE(max(id), 0) AS max_id, -- nextval(pg_get_serial_sequence('app_user.dis_event', 'id')) AS next_id -- FROM app_user.dis_event; -- 注意:如 pg_get_serial_sequence 在 KES 上返回空,则改用步骤 0 查到的序列名: -- SELECT nextval('app_user.dis_event_id_seq'); -- ---------------------------------------------------------------------