-- ============================================================ -- 存量数据回填脚本 -- 1. notice.sch_id:按发布人所属学校回填(从 sys_user_role_rel 取 main=1 的 sch_id) -- 2. notice_receiver:从 notice.receive_list JSON 字符串展开为关联表行 -- -- 幂等设计:可重复执行,已存在的数据不会重复插入 -- 执行方式:由 DBA 手动在对应环境执行,AI 不代跑 -- MySQL 5.7+ 兼容 -- ============================================================ -- ============================================================ -- Part 1:回填 notice.sch_id -- ============================================================ -- 方式一:如果 base_user / sys_user 表有 sch_id 字段,直接关联回填 -- 注意:需根据实际平台库表结构调整关联条件 UPDATE `notice` n INNER JOIN ( SELECT DISTINCT u.login_name, u.sch_id FROM base_user u WHERE u.sch_id IS NOT NULL ) t ON n.publisher_account = t.login_name SET n.sch_id = t.sch_id WHERE n.sch_id IS NULL AND n.publisher_account IS NOT NULL AND n.publisher_account != ''; -- 方式二(备用):如果用户学校关系在 sys_user_role_rel 表 -- 取每个用户的主身份学校(is_main=1),回填 sch_id -- 取消注释后执行(视实际库表结构选用) -- -- UPDATE `notice` n -- INNER JOIN ( -- SELECT r.account, r.sch_id -- FROM sys_user_role_rel r -- WHERE r.is_main = 1 -- AND r.sch_id IS NOT NULL -- ) t ON n.publisher_account = t.account -- SET n.sch_id = t.sch_id -- WHERE n.sch_id IS NULL -- AND n.publisher_account IS NOT NULL -- AND n.publisher_account != ''; -- ============================================================ -- Part 2:从 notice.receive_list 展开到 notice_receiver 关联表 -- ============================================================ -- 说明: -- - notice.receive_list 存储格式有两种: -- 1) "ALL"(全员通知)—— 不写明细行,跳过 -- 2) JSON 数组 ["account1","account2",...] 或逗号分隔串 -- - 本脚本使用 MySQL JSON 函数解析(MySQL 5.7+ 支持 JSON_EXTRACT) -- - 对于非标准 JSON 格式(逗号分隔串),使用循环逐条插入 -- - 幂等:每次插入前先删除该通知的旧接收人记录 -- 注意:MySQL 5.7 的 JSON_TABLE 不可用,这里用存储过程逐条解析 -- 如果 receive_list 是标准 JSON 数组格式,可以直接用 JSON_EXTRACT DELIMITER $$ -- 存储过程:展开单个通知的接收人列表 DROP PROCEDURE IF EXISTS `expand_notice_receivers`$$ CREATE PROCEDURE `expand_notice_receivers`() BEGIN DECLARE v_done INT DEFAULT 0; DECLARE v_notice_id INT; DECLARE v_receive_list TEXT; DECLARE cur CURSOR FOR SELECT id, receive_list FROM notice WHERE receive_list IS NOT NULL AND TRIM(receive_list) != '' AND UPPER(TRIM(receive_list)) != 'ALL' AND NOT EXISTS ( SELECT 1 FROM notice_receiver WHERE notice_id = notice.id LIMIT 1 ); DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = 1; OPEN cur; read_loop: LOOP FETCH cur INTO v_notice_id, v_receive_list; IF v_done = 1 THEN LEAVE read_loop; END IF; -- 清理旧数据(幂等) DELETE FROM notice_receiver WHERE notice_id = v_notice_id; -- 尝试 JSON 数组解析 -- receive_list 格式: ["account1","account2"] 或 account1,account2 SET v_receive_list = TRIM(v_receive_list); -- 去除首尾方括号(如有) IF LEFT(v_receive_list, 1) = '[' AND RIGHT(v_receive_list, 1) = ']' THEN SET v_receive_list = SUBSTRING(v_receive_list, 2, CHAR_LENGTH(v_receive_list) - 2); END IF; -- 替换引号为空,按逗号分隔 SET v_receive_list = REPLACE(REPLACE(v_receive_list, '"', ''), '''', ''); -- 逐条插入 -- 简单实现:用 FIND_IN_SET 不适用于变量,改用临时表 BEGIN DECLARE v_pos INT DEFAULT 1; DECLARE v_account VARCHAR(64); DECLARE v_remaining TEXT; SET v_remaining = v_receive_list; WHILE v_remaining IS NOT NULL AND TRIM(v_remaining) != '' DO IF LOCATE(',', v_remaining) > 0 THEN SET v_account = TRIM(SUBSTRING_INDEX(v_remaining, ',', 1)); SET v_remaining = SUBSTRING(v_remaining, LOCATE(',', v_remaining) + 1); ELSE SET v_account = TRIM(v_remaining); SET v_remaining = NULL; END IF; IF v_account != '' AND v_account IS NOT NULL THEN INSERT INTO notice_receiver (notice_id, account, receive_type, create_time) VALUES (v_notice_id, v_account, 1, NOW()); END IF; END WHILE; END; END LOOP; CLOSE cur; END$$ DELIMITER ; -- 执行存储过程 CALL expand_notice_receivers(); -- 清理临时存储过程 DROP PROCEDURE IF EXISTS `expand_notice_receivers`; -- ============================================================ -- 回填结果验证查询(执行后手动检查) -- ============================================================ -- 检查1:sch_id 回填覆盖率 -- SELECT -- COUNT(*) AS total, -- SUM(CASE WHEN sch_id IS NOT NULL THEN 1 ELSE 0 END) AS sch_id_filled, -- SUM(CASE WHEN sch_id IS NULL THEN 1 ELSE 0 END) AS sch_id_null -- FROM notice; -- 检查2:notice_receiver 展开行数 -- SELECT COUNT(*) FROM notice_receiver; -- 检查3:未展开的通知(receive_list 非空非 ALL 但 receiver 表无记录) -- SELECT n.id, n.receive_list -- FROM notice n -- LEFT JOIN notice_receiver r ON r.notice_id = n.id -- WHERE n.receive_list IS NOT NULL -- AND TRIM(n.receive_list) != '' -- AND UPPER(TRIM(n.receive_list)) != 'ALL' -- AND r.id IS NULL;