160 lines
5.8 KiB
SQL
160 lines
5.8 KiB
SQL
-- ============================================================
|
||
-- 存量数据回填脚本
|
||
-- 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;
|