dispatch_fix_all_identity.sql 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. -- =====================================================================
  2. -- dispatch_fix_all_identity.sql
  3. -- 一次性对齐 app_user 下所有 dis_* 表的主键自增序列
  4. -- ---------------------------------------------------------------------
  5. -- 背景:调度模块各表(dis_event / dis_event_log / dis_plan / dis_plan_version /
  6. -- dis_event_grade / dis_event_assess / dis_plan_log / dis_plan_library /
  7. -- dis_plan_match_record 等)由 MySQL 迁移至 Kingbase,迁移数据时带显式 id
  8. -- 插入,GENERATED BY DEFAULT AS IDENTITY 的序列不会自动推进;此后不带
  9. -- id 的 INSERT 会从序列起点发号(如发 0),撞已存在行,报主键冲突。
  10. -- 修复:遍历 app_user 下所有 dis_% 表,把 id 列关联的序列 setval 到 max(id)
  11. -- (setval(seq, max, true) → 下一个发号 = max+1)。幂等可重复执行。
  12. -- 执行方式:KingbaseES 客户端。逐段执行;某段失败先 ROLLBACK 再继续下一段。
  13. -- =====================================================================
  14. -- ---------------------------------------------------------------------
  15. -- 步骤 0(可选):先看各表现状——max(id) 与序列名,便于核对
  16. -- ---------------------------------------------------------------------
  17. SELECT c.relname AS 表名,
  18. (SELECT COALESCE(max(id), 0) FROM app_user.dis_event) AS 说明_另查,
  19. d.objid::regclass::text AS 关联序列
  20. FROM pg_class c
  21. JOIN pg_namespace n ON n.oid = c.relnamespace
  22. LEFT JOIN pg_depend d
  23. ON d.refobjid = c.oid
  24. AND d.classid = 'pg_class'::regclass
  25. AND d.deptype IN ('a', 'i')
  26. LEFT JOIN pg_attribute a
  27. ON a.attrelid = d.refobjid AND a.attnum = d.refobjsubid AND a.attname = 'id'
  28. WHERE n.nspname = 'app_user'
  29. AND c.relname LIKE 'dis_%'
  30. AND c.relkind = 'r';
  31. -- ---------------------------------------------------------------------
  32. -- 步骤 1(首选):自动遍历所有 dis_% 表,校准 id 序列
  33. -- 执行成功会逐表 NOTICE 输出「表名 -> 序列名 (next=...)」
  34. -- ---------------------------------------------------------------------
  35. DO $$
  36. DECLARE
  37. t record;
  38. seqname text;
  39. maxid bigint;
  40. BEGIN
  41. FOR t IN
  42. SELECT c.relname AS table_name
  43. FROM pg_class c
  44. JOIN pg_namespace n ON n.oid = c.relnamespace
  45. WHERE n.nspname = 'app_user'
  46. AND c.relname LIKE 'dis\_%' ESCAPE '\'
  47. AND c.relkind = 'r'
  48. LOOP
  49. EXECUTE format('SELECT COALESCE(max(id), 0) FROM app_user.%I', t.table_name) INTO maxid;
  50. -- 找 id 列关联的序列(serial=deptype a / identity=deptype i)
  51. SELECT d.objid::regclass::text INTO seqname
  52. FROM pg_depend d
  53. JOIN pg_attribute a ON a.attrelid = d.refobjid AND a.attnum = d.refobjsubid
  54. JOIN pg_class sc ON sc.oid = d.objid AND sc.relkind = 'S'
  55. JOIN pg_namespace sn ON sn.oid = sc.relnamespace AND sn.nspname = 'app_user'
  56. WHERE d.refobjid = format('app_user.%I', t.table_name)::regclass
  57. AND a.attname = 'id'
  58. AND d.classid = 'pg_class'::regclass
  59. AND d.deptype IN ('a', 'i')
  60. LIMIT 1;
  61. IF seqname IS NOT NULL THEN
  62. EXECUTE format('SELECT setval(%L::regclass, %s, true)', seqname, GREATEST(maxid, 1));
  63. RAISE NOTICE '% -> % (next=%)', t.table_name, seqname, maxid + 1;
  64. ELSE
  65. RAISE NOTICE '% -> 未找到关联序列,请用步骤 2 手工处理', t.table_name;
  66. END IF;
  67. END LOOP;
  68. END $$;
  69. -- ---------------------------------------------------------------------
  70. -- 步骤 2(保底):步骤 1 中提示「未找到关联序列」的表,手工对齐
  71. -- 先查该表 max(id),把下面的 <n> 替换为 max(id)(RESTART WITH 生效值即下一个发号):
  72. -- ALTER TABLE app_user.表名 ALTER COLUMN id RESTART WITH <max(id)>;
  73. --
  74. -- 例(编号仅为示例,以步骤 0 查到的 max(id) 为准):
  75. -- ALTER TABLE app_user.dis_event ALTER COLUMN id RESTART WITH 100;
  76. -- ALTER TABLE app_user.dis_event_log ALTER COLUMN id RESTART WITH 300;
  77. -- ALTER TABLE app_user.dis_event_assess ALTER COLUMN id RESTART WITH 10;
  78. -- ---------------------------------------------------------------------
  79. -- ---------------------------------------------------------------------
  80. -- 步骤 3:核验——逐表 nextval 应等于 max(id) + 1(多表循环核验可重复步骤 0)
  81. -- 示例:
  82. -- SELECT COALESCE(max(id), 0) AS max_id,
  83. -- nextval(pg_get_serial_sequence('app_user.dis_event', 'id')) AS next_id
  84. -- FROM app_user.dis_event;
  85. -- 注意:如 pg_get_serial_sequence 在 KES 上返回空,则改用步骤 0 查到的序列名:
  86. -- SELECT nextval('app_user.dis_event_id_seq');
  87. -- ---------------------------------------------------------------------