Files
BMS/bms-back/sql/customer+supplier/20261028_customer_sales_user_migration.sql
2026-10-28 22:19:47 +08:00

143 lines
6.5 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- MySQL 5.7
-- 客户业务员工号 -> 系统用户ID 存量迁移。
-- 上线前先执行 20261028_customer_sales_user_classification.sql 并核对 ID_USERNAME_COLLISION。
-- 自动转换仅处理唯一 user_name 匹配;未匹配、重复匹配和 ID/工号冲突会备份原值、清空 sales_user_id,留给管理员在客户编辑页处理。
-- 本脚本不连接数据库执行;可重复运行。完成标记写入后,重复运行不会再次处理存量或改写备份。
-- 新增内部源工号列(兼容 MySQL 5.7,不依赖 ADD COLUMN IF NOT EXISTS)。
SET @add_source_sales_code_sql = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE ctr_customer ADD COLUMN source_sales_code varchar(255) DEFAULT NULL COMMENT ''客户同步源业务员工号(内部字段)'' AFTER sales_user_id',
'SELECT 1')
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'ctr_customer'
AND column_name = 'source_sales_code'
);
PREPARE add_source_sales_code_stmt FROM @add_source_sales_code_sql;
EXECUTE add_source_sales_code_stmt;
DEALLOCATE PREPARE add_source_sales_code_stmt;
-- 未匹配时使用 NULL,避免空字符串伪装成用户ID。
ALTER TABLE ctr_customer
MODIFY COLUMN sales_user_id varchar(64) DEFAULT NULL COMMENT '业务员系统用户ID(sys_user.user_id)';
-- 备份表同时保留分类结果和候选ID;PRIMARY KEY + INSERT IGNORE 保证原始值不会被后续重跑覆盖。
CREATE TABLE IF NOT EXISTS ctr_customer_sales_user_migration_backup (
customer_id bigint(20) NOT NULL COMMENT '客户ID',
customer_code varchar(50) NOT NULL COMMENT '客户编码',
original_sales_user_id varchar(64) DEFAULT NULL COMMENT '迁移前 sales_user_id 原值',
classification varchar(40) NOT NULL COMMENT '迁移前分类',
user_id_match_count int NOT NULL DEFAULT 0 COMMENT '精确 user_id 匹配数',
user_name_match_count int NOT NULL DEFAULT 0 COMMENT '精确 user_name 匹配数',
user_id_candidates text COMMENT 'user_id 匹配候选',
user_name_candidates text COMMENT 'user_name 匹配候选',
backup_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '备份时间',
PRIMARY KEY (customer_id),
KEY idx_customer_sales_user_backup_classification (classification)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户业务员ID迁移原值及分类备份';
-- 防止成功执行后重跑时把后来新建/人工维护的客户重新当作存量数据处理。
CREATE TABLE IF NOT EXISTS ctr_customer_sales_user_migration_control (
migration_key varchar(64) NOT NULL,
status varchar(16) NOT NULL DEFAULT 'PENDING',
completed_at datetime DEFAULT NULL,
PRIMARY KEY (migration_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户业务员ID迁移执行状态';
INSERT IGNORE INTO ctr_customer_sales_user_migration_control (migration_key, status)
VALUES ('20261028_customer_sales_user', 'PENDING');
START TRANSACTION;
-- 首次运行时先保留旧值和候选;后续事务失败可安全重跑,成功后由 control 表阻止再次处理。
INSERT IGNORE INTO ctr_customer_sales_user_migration_backup (
customer_id, customer_code, original_sales_user_id, classification,
user_id_match_count, user_name_match_count, user_id_candidates, user_name_candidates
)
SELECT c.customer_id,
c.customer_code,
c.sales_user_id,
CASE
WHEN c.sales_user_id IS NULL OR TRIM(c.sales_user_id) = '' THEN 'EMPTY'
WHEN id_match.match_count > 0 AND name_match.match_count > 0 THEN 'ID_USERNAME_COLLISION'
WHEN id_match.match_count > 0 THEN 'VALID_USER_ID'
WHEN name_match.match_count = 1 THEN 'UNIQUE_USERNAME'
WHEN name_match.match_count > 1 THEN 'AMBIGUOUS_USERNAME'
ELSE 'NO_MATCH'
END,
COALESCE(id_match.match_count, 0),
COALESCE(name_match.match_count, 0),
id_match.candidate_user_ids,
name_match.candidate_user_ids
FROM ctr_customer c
JOIN ctr_customer_sales_user_migration_control migration
ON migration.migration_key = '20261028_customer_sales_user'
AND migration.status = 'PENDING'
LEFT JOIN (
SELECT CAST(user_id AS CHAR) AS lookup_value,
COUNT(*) AS match_count,
GROUP_CONCAT(CAST(user_id AS CHAR) ORDER BY user_id SEPARATOR ',') AS candidate_user_ids
FROM sys_user
WHERE del_flag = '0'
GROUP BY CAST(user_id AS CHAR)
) id_match ON BINARY id_match.lookup_value = BINARY TRIM(c.sales_user_id)
LEFT JOIN (
SELECT BINARY TRIM(user_name) AS lookup_value,
COUNT(*) AS match_count,
GROUP_CONCAT(CAST(user_id AS CHAR) ORDER BY user_id SEPARATOR ',') AS candidate_user_ids
FROM sys_user
WHERE del_flag = '0'
AND user_name IS NOT NULL
AND user_name != ''
GROUP BY BINARY TRIM(user_name)
) name_match ON name_match.lookup_value = BINARY TRIM(c.sales_user_id)
WHERE c.del_flag = '0'
AND c.source_sales_code IS NULL;
-- 唯一工号映射到系统用户ID;不唯一、不匹配或存在ID/工号冲突的项不猜测,清空关联并保留源值。
UPDATE ctr_customer c
JOIN ctr_customer_sales_user_migration_backup b
ON b.customer_id = c.customer_id
JOIN ctr_customer_sales_user_migration_control migration
ON migration.migration_key = '20261028_customer_sales_user'
AND migration.status = 'PENDING'
SET c.source_sales_code = b.original_sales_user_id,
c.sales_user_id = CASE
WHEN b.classification = 'UNIQUE_USERNAME'
THEN b.user_name_candidates
ELSE NULL
END
WHERE c.del_flag = '0'
AND c.source_sales_code IS NULL
AND b.classification IN (
'UNIQUE_USERNAME',
'AMBIGUOUS_USERNAME',
'NO_MATCH',
'ID_USERNAME_COLLISION'
);
-- 将旧空字符串归一为 NULL,已确认是系统用户ID的行保持不变。
UPDATE ctr_customer c
JOIN ctr_customer_sales_user_migration_control migration
ON migration.migration_key = '20261028_customer_sales_user'
AND migration.status = 'PENDING'
SET c.sales_user_id = NULL
WHERE c.del_flag = '0'
AND c.sales_user_id IS NOT NULL
AND TRIM(c.sales_user_id) = '';
UPDATE ctr_customer_sales_user_migration_control
SET status = 'DONE', completed_at = NOW()
WHERE migration_key = '20261028_customer_sales_user'
AND status = 'PENDING';
COMMIT;
-- 执行后核对人工处理清单;原值和候选均保存在备份表中。
SELECT customer_id, customer_code, original_sales_user_id, classification,
user_id_candidates, user_name_candidates
FROM ctr_customer_sales_user_migration_backup
WHERE classification IN ('ID_USERNAME_COLLISION', 'AMBIGUOUS_USERNAME', 'NO_MATCH')
ORDER BY classification, customer_id;