feat: 人资+机构同步

This commit is contained in:
2026-10-08 19:45:38 +08:00
parent 20bac2e078
commit 1650383670
12 changed files with 670 additions and 311 deletions
+2 -2
View File
@@ -61,8 +61,8 @@ custom:
password: 3848A3C738EFBB2C2E76E0D59B419DACA16A80F3AB0354CD
token-url: https://bd.whcp.zjnu.edu.cn/sjjkfwpt/api/bd-api/oauth/token
urls:
teacher: https://bd.whcp.zjnu.edu.cn/sjjkfwpt/api/bd-api/get/JZGJCSJZLB
unit: https://bd.whcp.zjnu.edu.cn/sjjkfwpt/api/bd-api/get/YXSDWJBSJZLB
teacher: http://mdm.zjnu.edu.cn/do/api/call/lxyxt_jzgjbxx
unit: http://mdm.zjnu.edu.cn/do/api/call/lxyxt_dwxx
msg:
platform:
enabled: false
+2 -2
View File
@@ -61,8 +61,8 @@ custom:
password: 3848A3C738EFBB2C2E76E0D59B419DACA16A80F3AB0354CD
token-url: https://bd.whcp.edu.cn/sjjkfwpt/api/bd-api/oauth/token
urls:
teacher: https://bd.whcp.edu.cn/sjjkfwpt/api/bd-api/get/JZGJCSJZLB
unit: https://bd.whcp.edu.cn/sjjkfwpt/api/bd-api/get/YXSDWJBSJZLB
teacher: http://mdm.zjnu.edu.cn/do/api/call/lxyxt_jzgjbxx
unit: http://mdm.zjnu.edu.cn/do/api/call/lxyxt_dwxx
msg:
platform:
enabled: false
@@ -0,0 +1,138 @@
-- 目标:浙江师范大学 -> 下级单位,不再显示额外的“组织机构”层。
-- 当前 v4 接口固定以 ID=0 构建树,因此将学校 ID=1 的信息合并到 ID=0。
-- 只修改 sys_unit;不修改人员、角色和业务数据。执行期间不要并发写入相关数据。
-- 检查其他表的机构 ID、机构 ID 数组及显式外键;存在对 ID=1 的引用时停止。
-- 备份表固定命名,不覆盖已有备份。本文件独立执行,不要嵌入已有事务。
DELIMITER $$
DROP PROCEDURE IF EXISTS zhgh_zjnu.merge_zjnu_school_root$$
CREATE PROCEDURE zhgh_zjnu.merge_zjnu_school_root()
BEGIN
DECLARE finished BOOLEAN DEFAULT FALSE;
DECLARE reference_table VARCHAR(64);
DECLARE reference_column VARCHAR(64);
DECLARE is_array BOOLEAN;
DECLARE error_message VARCHAR(128);
DECLARE root_has_children BOOLEAN;
DECLARE references_cursor CURSOR FOR
SELECT c.TABLE_NAME, c.COLUMN_NAME,
LOWER(c.COLUMN_NAME) LIKE '%unitids'
FROM information_schema.COLUMNS c
JOIN information_schema.TABLES t
ON t.TABLE_SCHEMA = c.TABLE_SCHEMA AND t.TABLE_NAME = c.TABLE_NAME
WHERE c.TABLE_SCHEMA = 'zhgh_zjnu' AND t.TABLE_TYPE = 'BASE TABLE'
AND c.TABLE_NAME <> 'sys_unit' AND LEFT(c.TABLE_NAME, 4) <> 'bak_'
AND (LOWER(c.COLUMN_NAME) LIKE '%unitid'
OR LOWER(c.COLUMN_NAME) LIKE '%unitids'
OR LOWER(c.COLUMN_NAME) = 'undertakeid'
OR EXISTS (
SELECT 1 FROM information_schema.KEY_COLUMN_USAGE k
WHERE k.TABLE_SCHEMA = c.TABLE_SCHEMA AND k.TABLE_NAME = c.TABLE_NAME
AND k.COLUMN_NAME = c.COLUMN_NAME
AND k.REFERENCED_TABLE_SCHEMA = 'zhgh_zjnu'
AND k.REFERENCED_TABLE_NAME = 'sys_unit'
AND k.REFERENCED_COLUMN_NAME = 'id'));
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = TRUE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
IF NOT EXISTS (SELECT 1 FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'zhgh_zjnu' AND TABLE_NAME = 'sys_unit' AND ENGINE = 'InnoDB') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'sys_unit 必须使用 InnoDB';
END IF;
IF NOT EXISTS (SELECT 1 FROM zhgh_zjnu.sys_unit
WHERE id = '1' AND name = '浙江师范大学' AND parentId = '0')
OR NOT EXISTS (SELECT 1 FROM zhgh_zjnu.sys_unit
WHERE id = '0' AND name = '组织机构') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '当前根节点与指定数据不一致,停止合并';
END IF;
IF EXISTS (SELECT 1 FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'zhgh_zjnu' AND TABLE_NAME = 'bak_sys_unit_before_school_root_merge') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '学校根节点合并备份已存在,不覆盖原备份';
END IF;
OPEN references_cursor;
reference_loop: LOOP
FETCH references_cursor INTO reference_table, reference_column, is_array;
IF finished THEN
LEAVE reference_loop;
END IF;
SET @school_root_reference = 0;
SET @school_root_check_sql = CONCAT(
'SELECT EXISTS (SELECT 1 FROM `zhgh_zjnu`.`', REPLACE(reference_table, '`', '``'),
'` WHERE ',
IF(is_array,
CONCAT('JSON_CONTAINS(`', REPLACE(reference_column, '`', '``'),
'`, JSON_QUOTE(''1'')) OR JSON_CONTAINS(`',
REPLACE(reference_column, '`', '``'), '`, ''1'')'),
CONCAT('CAST(`', REPLACE(reference_column, '`', '``'), '` AS CHAR) = ''1''')),
') INTO @school_root_reference');
PREPARE school_root_check_stmt FROM @school_root_check_sql;
EXECUTE school_root_check_stmt;
DEALLOCATE PREPARE school_root_check_stmt;
IF @school_root_reference = 1 THEN
SET error_message = LEFT(CONCAT('学校 ID=1 仍被引用:', reference_table, '.', reference_column), 128);
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = error_message;
END IF;
END LOOP;
CLOSE references_cursor;
CREATE TABLE zhgh_zjnu.bak_sys_unit_before_school_root_merge LIKE zhgh_zjnu.sys_unit;
INSERT INTO zhgh_zjnu.bak_sys_unit_before_school_root_merge SELECT * FROM zhgh_zjnu.sys_unit;
DROP TEMPORARY TABLE IF EXISTS zhgh_zjnu.tmp_school_root_merge;
CREATE TEMPORARY TABLE zhgh_zjnu.tmp_school_root_merge LIKE zhgh_zjnu.sys_unit;
START TRANSACTION;
INSERT INTO zhgh_zjnu.tmp_school_root_merge SELECT * FROM zhgh_zjnu.sys_unit WHERE id = '1';
-- 先调整下级,再删除已暂存的学校记录;现有 ID=0 本身不删除。
UPDATE zhgh_zjnu.sys_unit SET parentId = '0' WHERE parentId = '1';
DELETE FROM zhgh_zjnu.sys_unit WHERE id = '1';
SELECT EXISTS (SELECT 1 FROM zhgh_zjnu.sys_unit WHERE parentId = '0' AND id <> '0')
INTO root_has_children;
UPDATE zhgh_zjnu.sys_unit target
JOIN zhgh_zjnu.tmp_school_root_merge school ON school.id = '1'
SET target.parentId = '0',
target.path = school.path,
target.name = school.name,
target.aliasName = school.aliasName,
target.unitcode = school.unitcode,
target.note = school.note,
target.address = school.address,
target.telephone = school.telephone,
target.email = school.email,
target.website = school.website,
target.location = school.location,
target.hasChildren = root_has_children,
target.logo = school.logo,
target.unitLevel = school.unitLevel,
target.unionId = school.unionId,
target.unionGroupId = school.unionGroupId,
target.createdBy = school.createdBy,
target.createdAt = school.createdAt,
target.updatedBy = school.updatedBy,
target.updatedAt = school.updatedAt,
target.delFlag = school.delFlag,
target.divisionCollegeCode = school.divisionCollegeCode,
target.institutionType = school.institutionType,
target.unitType = school.unitType,
target.unitTypeCode = 0
WHERE target.id = '0';
COMMIT;
DROP TEMPORARY TABLE zhgh_zjnu.tmp_school_root_merge;
END$$
CALL zhgh_zjnu.merge_zjnu_school_root()$$
DROP PROCEDURE zhgh_zjnu.merge_zjnu_school_root$$
DELIMITER ;
@@ -0,0 +1,87 @@
-- 修复 v3 机构导入后 v4 单位树查询失败的问题,只操作 v4 的 sys_unit。
-- 目标库:zhgh_zjnu。独立执行本文件,期间不要并发修改机构数据。
-- 补齐 unitTypeCode;缺少 ID=0 的根节点时新增“组织机构”容器。
-- 保留现有机构 ID、path、工会关系及人员数据,原顶层机构挂到 ID=0 下。
-- 备份表不覆盖;存在同名备份时停止,防止覆盖首次修复前的数据。
DELIMITER $$
DROP PROCEDURE IF EXISTS zhgh_zjnu.repair_v4_unit_tree_after_v3_import$$
CREATE PROCEDURE zhgh_zjnu.repair_v4_unit_tree_after_v3_import()
BEGIN
DECLARE root_has_children BOOLEAN DEFAULT FALSE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
IF NOT EXISTS (SELECT 1 FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'zhgh_zjnu' AND TABLE_NAME = 'sys_unit' AND ENGINE = 'InnoDB') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '目标 sys_unit 必须存在且使用 InnoDB';
END IF;
IF NOT EXISTS (SELECT 1 FROM zhgh_zjnu.sys_unit) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '机构表为空,无法修复导入的单位树';
END IF;
IF EXISTS (SELECT 1 FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'zhgh_zjnu' AND TABLE_NAME = 'bak_sys_unit_before_tree_repair') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '单位树修复备份已存在,本次停止,不覆盖原备份';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu.sys_unit WHERE id = 'root') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '机构 ID=root 与接口虚拟根冲突,需明确 ID 映射后再处理';
END IF;
IF NOT EXISTS (SELECT 1 FROM zhgh_zjnu.sys_unit WHERE id = '0')
AND EXISTS (SELECT 1 FROM zhgh_zjnu.sys_unit WHERE unitcode = '0') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '机构编码 0 已被其他机构使用,停止新增根节点';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu.sys_unit child
LEFT JOIN zhgh_zjnu.sys_unit parent ON parent.id = child.parentId
WHERE child.id <> '0' AND COALESCE(TRIM(child.parentId), '') NOT IN ('', '0')
AND (parent.id IS NULL OR child.id = child.parentId)) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '存在缺失的父机构或非根节点自引用,不能自动确定归属';
END IF;
-- 建表放在修复事务之前;完整保留修复前机构数据。
CREATE TABLE zhgh_zjnu.bak_sys_unit_before_tree_repair LIKE zhgh_zjnu.sys_unit;
INSERT INTO zhgh_zjnu.bak_sys_unit_before_tree_repair SELECT * FROM zhgh_zjnu.sys_unit;
START TRANSACTION;
-- v3 没有此字段,一级及以上容器取 0,二级及下级部门取 1。
UPDATE zhgh_zjnu.sys_unit
SET unitTypeCode = CASE WHEN unitLevel >= 2 THEN 1 ELSE 0 END
WHERE unitTypeCode IS NULL;
IF NOT EXISTS (SELECT 1 FROM zhgh_zjnu.sys_unit WHERE id = '0') THEN
INSERT INTO zhgh_zjnu.sys_unit
(id, parentId, path, name, unitcode, location, hasChildren,
unitLevel, unitTypeCode, delFlag, createdAt, updatedAt)
VALUES
('0', '0', NULL, '组织机构', '0', 0, 0, 0, 0, 0,
CAST(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000 AS UNSIGNED),
CAST(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000 AS UNSIGNED));
END IF;
UPDATE zhgh_zjnu.sys_unit
SET parentId = '0'
WHERE id <> '0' AND COALESCE(TRIM(parentId), '') IN ('', '0');
SELECT EXISTS (SELECT 1 FROM zhgh_zjnu.sys_unit WHERE parentId = '0' AND id <> '0')
INTO root_has_children;
UPDATE zhgh_zjnu.sys_unit
SET parentId = '0', unitTypeCode = 0, hasChildren = root_has_children
WHERE id = '0';
COMMIT;
END$$
CALL zhgh_zjnu.repair_v4_unit_tree_after_v3_import()$$
DROP PROCEDURE zhgh_zjnu.repair_v4_unit_tree_after_v3_import$$
DELIMITER ;
@@ -0,0 +1,191 @@
-- 仅替换组织机构、组织工会,不修改人员、角色、工会小组及业务数据。
-- 按项目配置:同一 MySQL 8 实例,源库 zhgh_zjnu_v3,目标库 zhgh_zjnu。
-- 保留 v3 的主键和父子关系;v4 独有的机构字段仅在原 ID 相同时保留。
-- 本脚本需独立执行,期间不得有其他连接写入相关数据,不得嵌入已有事务。
-- 若现有人员或关联数据无法继续引用导入的 ID,直接报错,不自动清除关联。
-- 备份表使用固定名称且不覆盖;已存在时拒绝执行,避免丢失首次备份。
DELIMITER $$
DROP PROCEDURE IF EXISTS zhgh_zjnu.replace_v4_unit_union_from_v3$$
CREATE PROCEDURE zhgh_zjnu.replace_v4_unit_union_from_v3()
BEGIN
DECLARE backup_created BOOLEAN DEFAULT FALSE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
DECLARE EXIT HANDLER FOR SQLWARNING
BEGIN
ROLLBACK;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '字段转换产生警告,替换已回滚;请核对源字段长度和类型';
END;
IF (SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'zhgh_zjnu' AND TABLE_NAME IN ('sys_unit', 'sys_union')
AND ENGINE = 'InnoDB') <> 2 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '目标机构、工会表必须存在且使用 InnoDB';
END IF;
IF EXISTS (SELECT 1 FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'zhgh_zjnu'
AND TABLE_NAME IN ('bak_sys_unit_before_v3_replace', 'bak_sys_union_before_v3_replace')) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '替换备份表已存在,本次停止,不覆盖原备份';
END IF;
DROP TEMPORARY TABLE IF EXISTS tmp_v3_replace_unit;
DROP TEMPORARY TABLE IF EXISTS tmp_v3_replace_union;
CREATE TEMPORARY TABLE tmp_v3_replace_unit LIKE zhgh_zjnu.sys_unit;
CREATE TEMPORARY TABLE tmp_v3_replace_union LIKE zhgh_zjnu.sys_union;
IF NOT EXISTS (SELECT 1 FROM zhgh_zjnu_v3.sys_unit)
OR NOT EXISTS (SELECT 1 FROM zhgh_zjnu_v3.sys_union) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'v3 机构或工会为空,停止清除 v4 数据';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu_v3.sys_unit
WHERE id IS NULL OR TRIM(id) = '' OR CHAR_LENGTH(id) > 32
OR CHAR_LENGTH(parentId) > 32 OR CHAR_LENGTH(unitcode) > 32) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'v3 机构 ID、父 ID 或编码不符合 v4 长度要求';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu_v3.sys_union
WHERE id IS NULL OR TRIM(id) = '') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'v3 存在空工会 ID,停止替换';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu_v3.sys_unit child
LEFT JOIN zhgh_zjnu_v3.sys_unit parent ON parent.id = child.parentId
WHERE COALESCE(child.parentId, '') NOT IN ('', '0') AND parent.id IS NULL) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'v3 机构存在缺失的父机构,停止替换';
END IF;
-- 按目标表结构暂存,唯一键冲突和字段转换异常均发生在清除数据之前。
INSERT INTO tmp_v3_replace_union
(id, name, unionCode, telephone, campus, createdBy, createdAt, updatedBy, updatedAt, delFlag)
SELECT id, unionname, unioncode, telephone, campus, '',
CAST(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000 AS UNSIGNED), '',
CAST(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000 AS UNSIGNED), 0
FROM zhgh_zjnu_v3.sys_union;
INSERT INTO tmp_v3_replace_unit
(id, parentId, path, name, aliasName, unitcode, note, address, telephone,
email, website, location, hasChildren, logo, unitLevel, unionId, unionGroupId,
createdBy, createdAt, updatedBy, updatedAt, delFlag)
SELECT id, parentId, path, name, aliasName, unitcode, note, address, telephone,
email, website, location, hasChildren, logo, unitlevel, unionid, unionGroupId,
createdBy, createdAt, updatedBy, updatedAt, COALESCE(delFlag, 0)
FROM zhgh_zjnu_v3.sys_unit;
UPDATE tmp_v3_replace_unit incoming
JOIN zhgh_zjnu.sys_unit existing ON existing.id = incoming.id
SET incoming.divisionCollegeCode = existing.divisionCollegeCode,
incoming.institutionType = existing.institutionType,
incoming.unitType = existing.unitType,
incoming.unitTypeCode = existing.unitTypeCode;
IF EXISTS (SELECT 1 FROM tmp_v3_replace_unit unit
LEFT JOIN tmp_v3_replace_union union_info ON union_info.id = unit.unionId
WHERE COALESCE(unit.unionId, '') <> '' AND union_info.id IS NULL) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'v3 机构引用的工会不存在,停止替换';
END IF;
-- 人员暂时不动:机构 ID、三级机构 ID、组织路径必须仍然有效。
IF EXISTS (SELECT 1 FROM zhgh_zjnu.sys_user user_info
LEFT JOIN tmp_v3_replace_unit unit ON unit.id = user_info.unitId
WHERE COALESCE(user_info.unitId, '') <> ''
AND (unit.id IS NULL OR (COALESCE(user_info.unitPath, '') <> ''
AND NOT (user_info.unitPath <=> unit.path)))) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有人员机构 ID 或路径与 v3 不兼容;人员不动时不能直接替换';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu.sys_user user_info
LEFT JOIN tmp_v3_replace_unit unit ON unit.id = user_info.threeUnitId
WHERE COALESCE(user_info.threeUnitId, '') <> '' AND unit.id IS NULL) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有人员的三级机构不在 v3 中,停止替换';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu.sys_user_unit relation_info
LEFT JOIN tmp_v3_replace_unit unit ON unit.id = relation_info.unitId
WHERE COALESCE(relation_info.unitId, '') <> '' AND unit.id IS NULL) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有人员兼职机构不在 v3 中,停止替换';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu.sys_role role_info
LEFT JOIN tmp_v3_replace_unit unit ON unit.id = role_info.unitid
WHERE COALESCE(role_info.unitid, '') <> '' AND unit.id IS NULL) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有角色所属机构不在 v3 中,停止替换';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu.sys_user_role relation_info
LEFT JOIN tmp_v3_replace_unit unit ON unit.id = relation_info.unitId
LEFT JOIN tmp_v3_replace_union union_info ON union_info.id = relation_info.unionId
WHERE (COALESCE(relation_info.unitId, '') <> '' AND unit.id IS NULL)
OR (COALESCE(relation_info.unionId, '') <> '' AND union_info.id IS NULL)) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有用户权限范围引用了 v3 中不存在的机构或工会';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu.sys_branch_union_user_permission permission_info
LEFT JOIN tmp_v3_replace_union union_info ON union_info.id = permission_info.unionId
WHERE COALESCE(permission_info.unionId, '') <> '' AND union_info.id IS NULL) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有分工会人员授权引用的工会不在 v3 中';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu.special_staff staff
LEFT JOIN tmp_v3_replace_union union_info ON BINARY union_info.id = BINARY staff.unionRelationUnionId
WHERE COALESCE(staff.unionRelationUnionId, '') <> '' AND union_info.id IS NULL) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '特殊人员工会关系引用的工会不在 v3 中';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu.sys_union_cadre cadre
LEFT JOIN tmp_v3_replace_union union_info ON union_info.id = cadre.unionId
WHERE COALESCE(cadre.unionId, '') <> '' AND union_info.id IS NULL) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有工会干部引用的工会不在 v3 中';
END IF;
-- 工会小组不在本次替换范围,不能写入缺失或归属不一致的小组 ID。
IF EXISTS (SELECT 1 FROM tmp_v3_replace_unit unit
LEFT JOIN zhgh_zjnu.sys_union_group group_info ON group_info.id = unit.unionGroupId
WHERE COALESCE(unit.unionGroupId, '') <> ''
AND (group_info.id IS NULL OR NOT (group_info.unionId <=> unit.unionId))) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'v3 机构的小组关系与 v4 不兼容,需另行明确小组迁移范围';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu.sys_union_group group_info
LEFT JOIN tmp_v3_replace_union union_info ON union_info.id = group_info.unionId
WHERE COALESCE(group_info.unionId, '') <> '' AND union_info.id IS NULL) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有工会小组所属工会不在 v3 中';
END IF;
IF EXISTS (SELECT 1 FROM zhgh_zjnu.sys_union_group group_info
JOIN JSON_TABLE(COALESCE(group_info.unitIds, JSON_ARRAY()), '$[*]'
COLUMNS (unitId VARCHAR(100) PATH '$')) binding
LEFT JOIN tmp_v3_replace_unit unit ON BINARY unit.id = BINARY binding.unitId
WHERE unit.id IS NULL OR NOT (unit.unionId <=> group_info.unionId)) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有工会小组绑定机构与 v3 不兼容,停止替换';
END IF;
-- DDL 放在事务之前,避免创建备份表导致替换事务被隐式提交。
CREATE TABLE zhgh_zjnu.bak_sys_unit_before_v3_replace LIKE zhgh_zjnu.sys_unit;
CREATE TABLE zhgh_zjnu.bak_sys_union_before_v3_replace LIKE zhgh_zjnu.sys_union;
SET backup_created = TRUE;
START TRANSACTION;
INSERT INTO zhgh_zjnu.bak_sys_unit_before_v3_replace SELECT * FROM zhgh_zjnu.sys_unit;
INSERT INTO zhgh_zjnu.bak_sys_union_before_v3_replace SELECT * FROM zhgh_zjnu.sys_union;
DELETE FROM zhgh_zjnu.sys_unit;
DELETE FROM zhgh_zjnu.sys_union;
INSERT INTO zhgh_zjnu.sys_union SELECT * FROM tmp_v3_replace_union;
INSERT INTO zhgh_zjnu.sys_unit SELECT * FROM tmp_v3_replace_unit;
COMMIT;
DROP TEMPORARY TABLE tmp_v3_replace_unit;
DROP TEMPORARY TABLE tmp_v3_replace_union;
END$$
CALL zhgh_zjnu.replace_v4_unit_union_from_v3()$$
DROP PROCEDURE zhgh_zjnu.replace_v4_unit_union_from_v3$$
DELIMITER ;