Files
BMS/bms-back/sql/20261019_prod_ar_bill_unified_migration.sql
T
2026-10-19 15:52:57 +08:00

294 lines
11 KiB
SQL

-- =============================================================
-- 生产环境统一迁移脚本:应收账单用户归属字段及日志操作人ID迁移
-- 本脚本不包含 ar_bill_export 表改名。
-- 执行前确认目标库已存在 ar_bill_detail_export 表,并确认当前连接为生产库。
-- 本脚本包含字段新增/改名、历史数据回填、日志字段转换及索引整理。
-- =============================================================
-- 1. ar_bill 增加 create_user_id,并放到 confirmed_time 之后
-- -------------------------------------------------------------
SET @column_exists := (
SELECT COUNT(1) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill'
AND COLUMN_NAME = 'create_user_id'
);
SET @sql := IF(@column_exists = 0,
'ALTER TABLE `ar_bill` ADD COLUMN `create_user_id` bigint(20) DEFAULT NULL COMMENT ''创建用户ID'' AFTER `confirmed_time`',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 字段已存在时统一放到 confirmed_time 后(幂等,位置一致时无副作用)
ALTER TABLE `ar_bill`
MODIFY COLUMN `create_user_id` bigint(20) DEFAULT NULL COMMENT '创建用户ID' AFTER `confirmed_time`;
-- -------------------------------------------------------------
-- 2. ar_bill_detail_export 增加 export_user_id,兼容旧字段 create_user_id
-- -------------------------------------------------------------
SET @export_create_user_id_exists := (
SELECT COUNT(1) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_detail_export'
AND COLUMN_NAME = 'create_user_id'
);
SET @export_user_id_exists := (
SELECT COUNT(1) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_detail_export'
AND COLUMN_NAME = 'export_user_id'
);
-- 2.1 旧列存在、新列不存在:直接改名
SET @sql := IF(@export_create_user_id_exists > 0 AND @export_user_id_exists = 0,
'ALTER TABLE `ar_bill_detail_export` CHANGE COLUMN `create_user_id` `export_user_id` bigint(20) DEFAULT NULL COMMENT ''导出用户ID'' AFTER `export_status`',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 2.2 新列不存在(旧列也不存在):新增
SET @export_user_id_exists := (
SELECT COUNT(1) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_detail_export'
AND COLUMN_NAME = 'export_user_id'
);
SET @sql := IF(@export_user_id_exists = 0,
'ALTER TABLE `ar_bill_detail_export` ADD COLUMN `export_user_id` bigint(20) DEFAULT NULL COMMENT ''导出用户ID'' AFTER `export_status`',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 2.3 新旧列同时存在:保留新列已有值,用旧列补空
SET @export_create_user_id_exists := (
SELECT COUNT(1) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_detail_export'
AND COLUMN_NAME = 'create_user_id'
);
SET @sql := IF(@export_create_user_id_exists > 0,
'UPDATE `ar_bill_detail_export` SET `export_user_id` = `create_user_id` WHERE `export_user_id` IS NULL AND `create_user_id` IS NOT NULL',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 2.4 删除旧列
SET @sql := IF(@export_create_user_id_exists > 0,
'ALTER TABLE `ar_bill_detail_export` DROP COLUMN `create_user_id`',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 2.5 统一 export_user_id 位置到 export_by 前(幂等)
ALTER TABLE `ar_bill_detail_export`
MODIFY COLUMN `export_user_id` bigint(20) DEFAULT NULL COMMENT '导出用户ID' AFTER `export_status`;
-- -------------------------------------------------------------
-- 3. ar_bill_generate_task 增加 create_user_id,并放到 request_token 之后
-- -------------------------------------------------------------
SET @column_exists := (
SELECT COUNT(1) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_generate_task'
AND COLUMN_NAME = 'create_user_id'
);
SET @sql := IF(@column_exists = 0,
'ALTER TABLE `ar_bill_generate_task` ADD COLUMN `create_user_id` bigint(20) DEFAULT NULL COMMENT ''创建用户ID'' AFTER `request_token`',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
ALTER TABLE `ar_bill_generate_task`
MODIFY COLUMN `create_user_id` bigint(20) DEFAULT NULL COMMENT '创建用户ID' AFTER `request_token`;
-- -------------------------------------------------------------
-- 4. 按登录名补齐历史账单和异步任务的创建用户ID
-- 两边都加 COLLATE,确保 general_ci / unicode_ci 混用时不报 1267。
-- -------------------------------------------------------------
UPDATE `ar_bill`
INNER JOIN `sys_user`
ON `sys_user`.`user_name` COLLATE utf8mb4_unicode_ci = `ar_bill`.`create_by` COLLATE utf8mb4_unicode_ci
SET `ar_bill`.`create_user_id` = `sys_user`.`user_id`
WHERE `ar_bill`.`create_user_id` IS NULL;
UPDATE `ar_bill_detail_export`
INNER JOIN `sys_user`
ON `sys_user`.`user_name` COLLATE utf8mb4_unicode_ci = `ar_bill_detail_export`.`export_by` COLLATE utf8mb4_unicode_ci
SET `ar_bill_detail_export`.`export_user_id` = `sys_user`.`user_id`
WHERE `ar_bill_detail_export`.`export_user_id` IS NULL;
UPDATE `ar_bill_generate_task`
INNER JOIN `sys_user`
ON `sys_user`.`user_name` COLLATE utf8mb4_unicode_ci = `ar_bill_generate_task`.`create_by` COLLATE utf8mb4_unicode_ci
SET `ar_bill_generate_task`.`create_user_id` = `sys_user`.`user_id`
WHERE `ar_bill_generate_task`.`create_user_id` IS NULL;
-- -------------------------------------------------------------
-- 5. 兼容曾加过 ar_bill_log.create_user_id 的库:
-- 先把 create_user_id 迁入 operator_id,再删除重复列。
-- -------------------------------------------------------------
SET @log_create_user_id_exists := (
SELECT COUNT(1) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_log'
AND COLUMN_NAME = 'create_user_id'
);
-- 5.1 迁移前先把 operator_name 空值用 operator_id 字符串补齐
SET @sql := IF(@log_create_user_id_exists > 0,
'UPDATE `ar_bill_log` SET `operator_name` = CAST(`operator_id` AS CHAR) WHERE (`operator_name` IS NULL OR `operator_name` = '''') AND `operator_id` IS NOT NULL',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 5.2 把 create_user_id 迁入 operator_id
SET @sql := IF(@log_create_user_id_exists > 0,
'UPDATE `ar_bill_log` SET `operator_id` = CAST(`create_user_id` AS CHAR) WHERE `create_user_id` IS NOT NULL',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 5.3 删除重复列
SET @sql := IF(@log_create_user_id_exists > 0,
'ALTER TABLE `ar_bill_log` DROP COLUMN `create_user_id`',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- -------------------------------------------------------------
-- 6. ar_bill_log.operator_id 处理
-- 目标:operator_id 最终为 bigint(20) NULL,存 sys_user.user_id。
-- 流程:先确保可空 -> 若为字符串则把登录名/数字映射成用户ID -> 最后统一改成 bigint。
-- -------------------------------------------------------------
-- 6.1 先确保 operator_id 可空(否则后面 UPDATE 置 NULL 会失败)
SET @operator_id_nullable := (
SELECT IS_NULLABLE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_log'
AND COLUMN_NAME = 'operator_id'
);
SET @sql := IF(@operator_id_nullable <> 'YES',
'ALTER TABLE `ar_bill_log` MODIFY COLUMN `operator_id` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT ''操作人ID''',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 6.2 重新读取类型
SET @operator_id_type := (
SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_log'
AND COLUMN_NAME = 'operator_id'
);
-- 6.3 若 operator_id 为字符串:先用 operator_id 补齐 operator_name 空值
SET @sql := IF(@operator_id_type <> 'bigint',
'UPDATE `ar_bill_log` SET `operator_name` = CAST(`operator_id` AS CHAR) WHERE (`operator_name` IS NULL OR `operator_name` = '''') AND `operator_id` IS NOT NULL',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 6.4 若 operator_id 为字符串:登录名 -> sys_user.user_id;纯数字保留;其余置 NULL
SET @sql := IF(@operator_id_type <> 'bigint',
'UPDATE `ar_bill_log` l
LEFT JOIN `sys_user` u
ON u.`user_name` COLLATE utf8mb4_unicode_ci = l.`operator_id` COLLATE utf8mb4_unicode_ci
SET l.`operator_id` = CASE
WHEN u.`user_id` IS NOT NULL THEN CAST(u.`user_id` AS CHAR)
WHEN CAST(l.`operator_id` AS CHAR) REGEXP ''^[0-9]+$'' THEN CAST(l.`operator_id` AS CHAR)
ELSE NULL END
WHERE l.`operator_id` IS NOT NULL',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 6.5 最终统一改成 bigint(20) NULL
SET @operator_id_type := (
SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_log'
AND COLUMN_NAME = 'operator_id'
);
SET @operator_id_nullable := (
SELECT IS_NULLABLE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_log'
AND COLUMN_NAME = 'operator_id'
);
SET @sql := IF(@operator_id_type <> 'bigint' OR @operator_id_nullable <> 'YES',
'ALTER TABLE `ar_bill_log` MODIFY COLUMN `operator_id` bigint(20) DEFAULT NULL COMMENT ''操作人用户ID''',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- -------------------------------------------------------------
-- 7. ar_bill_generate_task 索引:确保 idx_ar_bill_generate_creator
-- 以 create_user_id 为首列。
-- -------------------------------------------------------------
SET @creator_index_exists := (
SELECT COUNT(1) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_generate_task'
AND INDEX_NAME = 'idx_ar_bill_generate_creator'
);
SET @creator_index_user_id_exists := (
SELECT COUNT(1) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_generate_task'
AND INDEX_NAME = 'idx_ar_bill_generate_creator'
AND COLUMN_NAME = 'create_user_id'
AND SEQ_IN_INDEX = 1
);
-- 7.1 旧索引存在但不以 create_user_id 为首列:先删
SET @sql := IF(@creator_index_exists > 0 AND @creator_index_user_id_exists = 0,
'ALTER TABLE `ar_bill_generate_task` DROP INDEX `idx_ar_bill_generate_creator`',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 7.2 重新读取,确认需要创建
SET @creator_index_user_id_exists := (
SELECT COUNT(1) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'ar_bill_generate_task'
AND INDEX_NAME = 'idx_ar_bill_generate_creator'
AND COLUMN_NAME = 'create_user_id'
AND SEQ_IN_INDEX = 1
);
SET @sql := IF(@creator_index_user_id_exists = 0,
'ALTER TABLE `ar_bill_generate_task` ADD KEY `idx_ar_bill_generate_creator` (`create_user_id`,`status`,`create_time`)',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;