iotsaas/backend/sql/V27__fix_mojibake_history_data.sql
2995840376 4c8aa5459d fix(N): V27 通用回转修复历史遗留的双重编码中文
问题: V26 只按 code 修好了 8 条预设品类, V25 回填的 2210/4120 备注仍是乱码; 全库体检还发现 V22 迁移写入的 platform_type 字典表 8 条名称/备注全部双重编码。

修法: 用 CONVERT(CAST(CONVERT(col USING latin1) AS BINARY) USING utf8mb4) 把 latin1 误解后的字符转回原始字节再按 utf8mb4 重新解释; 仅对 HEX 含 C2xx/C3xx 特征的值生效, 修完不再命中, 因此幂等可重复执行; platform_type 表做存在性判断, 旧结构库也能整段跑完。

验证: 生产 remaining_mojibake=0; 品类接口返回字节为正确 UTF-8(照明=e785a7e6988e); platform_type 涂鸦智能=e6b682e9b8a6e699bae883bd。
2026-10-28 08:55:03 +08:00

47 lines
2.3 KiB
SQL
Raw 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.

-- =====================================================================
-- V27 · 修复历史遗留的双重编码中文(通用回转)
-- ---------------------------------------------------------------------
-- 现象:后台「品类管理」备注、以及「平台类型」字典的名称/备注显示乱码。
--
-- 成因:V22 / V25 迁移执行时,服务器 mysql 客户端 character_set_client 为 latin1
-- (容器 C locale),UTF-8 字节被按 latin1 解读后再存入 utf8mb4 列
-- → 中文双重编码("涂鸦智能" 变成 C3A6C2B6E2809A...)。
--
-- 治本(已完成,后续迁移不会再犯):
-- - deploy-all.bat 的 mysql 调用已加 --default-character-set=utf8mb4;
-- - V25 / V26 脚本首行已加 SET NAMES utf8mb4。
-- 本脚本负责把历史数据修回来。
--
-- 修法:把 latin1 误解后的字符按 latin1 转回原始字节,再按 utf8mb4 重新解释:
-- CONVERT(CAST(CONVERT(col USING latin1) AS BINARY) USING utf8mb4)
-- 幂等:仅对仍含双重编码特征(HEX 含 C2xx / C3xx)的值生效,修完不再命中。
--
-- 无存储过程、无 DELIMITER;幂等可重复执行。
-- =====================================================================
SET NAMES utf8mb4;
-- ---------- 1) 平台类型字典(V22 写入;表可能不存在,做存在性判断) ----------
SET @has_pt = (SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'platform_type');
SET @s = IF(@has_pt > 0,
'UPDATE platform_type
SET name = CONVERT(CAST(CONVERT(name USING latin1) AS BINARY) USING utf8mb4),
remark = CONVERT(CAST(CONVERT(remark USING latin1) AS BINARY) USING utf8mb4),
update_time = NOW()
WHERE deleted = 0
AND (HEX(IFNULL(name, '''')) REGEXP ''C[23][0-9A-F]{2}''
OR HEX(IFNULL(remark, '''')) REGEXP ''C[23][0-9A-F]{2}'')',
'SELECT ''platform_type table not found, skipped'' AS info');
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ---------- 2) 品类字典备注(V25 回填历史品类时写入) ----------
UPDATE product_category
SET remark = CONVERT(CAST(CONVERT(remark USING latin1) AS BINARY) USING utf8mb4),
update_time = NOW()
WHERE deleted = 0
AND HEX(IFNULL(remark, '')) REGEXP 'C[23][0-9A-F]{2}';