merge: #64 学院标识一次性回填脚本

This commit is contained in:
2026-11-03 22:29:48 +08:00
+407
View File
@@ -0,0 +1,407 @@
-- ============================================================================
-- spec #58 / T6(issue #64):4 张在跑业务表的 college_id 一次性回填
--
-- 做什么:把「申报记录 → 申报人所在学院」写进 college_id。学院标识与
-- gxmu_student.college_id 是同一套 ID,都指向 sys_organization.organization_id
-- (见 docs/research/sso-org-data.md:24、ADR 0006「学院标识」)。
--
-- 执行顺序(不可打乱):
-- 1) 先执行 sql/20261110_spec58_approval_chain.sql(#59),它负责加 4 个 college_id 列。
-- 2) 整文件执行一次本脚本(mysql < 本文件)。文件内的段落顺序即执行顺序:
-- 0) 前置检查(只读) —— 先确认列在、名册有学院数据,否则后面的回填全是空转
-- 1) A 段 学生档案主路径 —— 申报记录 user_id → gxmu_student.college_id
-- 2) B 段 表单文本兜底 —— A 段后仍为空的行,用表单里的学院文本按组织名 LIKE 匹配
-- 3) 校验与清单(只读) —— 回填率、空值清单、未匹配文本一览,抄进上线记录
-- 3) ⚠ 只执行一次,不接定时任务。
--
-- 可重复执行:所有 UPDATE 都带「只填空、不覆盖」条件(college_id IS NULL),且不带会话状态
-- (不用临时表、不用视图),任何一句都可以单独重跑。重跑不会改掉人工修对的值。
--
-- 回滚:
-- #59 加列时 4 个 college_id 都是 NULL,本脚本只把 NULL 填成值,所以回滚就是把它们放回 NULL。
-- 执行前若已有人工填过的值,先自行快照(示例,取消注释后单独执行):
-- -- CREATE TABLE bak_20261110_college_id (module VARCHAR(64), rid BIGINT UNSIGNED, college_id INT, PRIMARY KEY (module, rid));
-- -- INSERT INTO bak_20261110_college_id SELECT 'gxmu_sjqn', id, college_id FROM gxmu_sjqn WHERE college_id IS NOT NULL;
-- (另 3 张表同形,module 换表名即可。)
-- 回滚语句见文件末尾「回滚」段,默认注释掉,避免整文件执行时误清空。
--
-- 口径(写清楚,避免二次解释):
-- * 「学院」以学生档案 gxmu_student.college_id 为准,它存的是 sys_organization.organization_id,
-- 与 gxmu_college.id 不是一套(缺口 G1,见调研文档)。本脚本不碰 gxmu_college。
-- * 学生档案优先取 status = 1(在校)那条的学院;同一 user_id 下学院不唯一时留空、不猜。
-- * 文本兜底只在「文本里恰好出现一个候选学院组织名」时写入;命中 0 个或多个都留空进清单。
-- * 候选学院节点 = 有平台单位号的节点(organization_code 非空,即开放平台同步的院系)
-- ∪ 学生档案实际引用过的节点。这样既不会把「药学院党委」这类手工节点当学院,
-- 也不用把学校根节点 ID 硬编码进脚本。
-- * 只处理 deleted = 0 的行;软删记录不参与回填,也不进回填率分母。
-- * 只按 user_id 关联学生(sys_user.user_id 全局唯一),tenant_id 不参与匹配。
-- * 不做学院层级推导、不建缺失的组织节点;匹配不上就是留空进清单。
-- ============================================================================
-- ---------------------------------------------------------------------------
-- 0) 前置检查(只读)
-- college_id_columns 期望 4;students_with_college 期望 > 0(为 0 说明名册还没同步,先别跑回填)。
-- ---------------------------------------------------------------------------
SELECT COUNT(*) AS college_id_columns
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME IN ('gxmu_sjqn', 'gxmu_tzbcy_form', 'gxmu_qmgc_form', 'gxmu_wxxzx_project')
AND COLUMN_NAME = 'college_id';
SELECT COUNT(*) AS students_with_college
FROM gxmu_student
WHERE deleted = 0 AND college_id IS NOT NULL;
-- ---------------------------------------------------------------------------
-- 1) A 段:学生档案主路径(以 gxmu_student.college_id 为准)
-- 同一个人(user_id)在名册里可能有多条:本科毕业的旧行 + 在读研究生行。
-- 取法:该 user_id 下学院唯一 → 直接用它;学院不唯一但「在校(status = 1)的学院」唯一
-- → 用在校那条的学院(同一个人的本科学院与研究生学院不同时,以在修为准)。
-- 两者都不满足 → 留空,不猜,交给 B 段文本或人工。
-- 只填空:WHERE t.college_id IS NULL;软删行与无申报人的行不处理。
-- no-op 说明:子查询无匹配行时 CASE 返回 NULL,等于把 NULL 再写一遍,不会破坏任何值。
-- ---------------------------------------------------------------------------
UPDATE gxmu_sjqn t
SET college_id = (
SELECT CASE
WHEN COUNT(DISTINCT s.college_id) = 1 THEN MIN(s.college_id)
WHEN COUNT(DISTINCT CASE WHEN s.status = 1 THEN s.college_id END) = 1
THEN MIN(CASE WHEN s.status = 1 THEN s.college_id END)
END
FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL
)
WHERE t.college_id IS NULL AND t.deleted = 0 AND t.user_id IS NOT NULL;
UPDATE gxmu_tzbcy_form t
SET college_id = (
SELECT CASE
WHEN COUNT(DISTINCT s.college_id) = 1 THEN MIN(s.college_id)
WHEN COUNT(DISTINCT CASE WHEN s.status = 1 THEN s.college_id END) = 1
THEN MIN(CASE WHEN s.status = 1 THEN s.college_id END)
END
FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL
)
WHERE t.college_id IS NULL AND t.deleted = 0 AND t.user_id IS NOT NULL;
UPDATE gxmu_qmgc_form t
SET college_id = (
SELECT CASE
WHEN COUNT(DISTINCT s.college_id) = 1 THEN MIN(s.college_id)
WHEN COUNT(DISTINCT CASE WHEN s.status = 1 THEN s.college_id END) = 1
THEN MIN(CASE WHEN s.status = 1 THEN s.college_id END)
END
FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL
)
WHERE t.college_id IS NULL AND t.deleted = 0 AND t.user_id IS NOT NULL;
UPDATE gxmu_wxxzx_project t
SET college_id = (
SELECT CASE
WHEN COUNT(DISTINCT s.college_id) = 1 THEN MIN(s.college_id)
WHEN COUNT(DISTINCT CASE WHEN s.status = 1 THEN s.college_id END) = 1
THEN MIN(CASE WHEN s.status = 1 THEN s.college_id END)
END
FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL
)
WHERE t.college_id IS NULL AND t.deleted = 0 AND t.user_id IS NOT NULL;
-- ---------------------------------------------------------------------------
-- 2) B 段:表单文本兜底(A 段后仍为空的行)
-- 每张表的学院列名不同,逐个写(见 issue #64):
-- gxmu_sjqn.unit_name / gxmu_tzbcy_form.school_name /
-- gxmu_qmgc_form.school_info / gxmu_wxxzx_project.college_grade_class
-- 匹配方式:文本里包含某个候选学院的完整组织名(LIKE '%组织名%')。
-- 只有「恰好命中 1 个候选学院」才写入;命中 0 个或多个一律留空,进 3b/3c 的清单。
-- 候选学院节点 = 有平台单位号(organization_code 非空,开放平台同步的院系)
-- ∪ 学生档案实际引用过的组织节点。
-- 这样排除「药学院党委」「护理学院团委」这类手工节点,
-- 也不用把学校根节点 ID(24)硬编码进脚本。
-- 组织名为空的节点先排除:空名会成为 LIKE '%%' 匹配一切,把每行都变成「多义」。
-- 已知误配风险(文本包含关系,故意不猜):见 DONE 的 notes。
-- ---------------------------------------------------------------------------
-- gxmu_sjqn.unit_name(所在单位)
UPDATE gxmu_sjqn t
SET college_id = (
SELECT CASE WHEN COUNT(*) = 1 THEN MIN(o.organization_id) END
FROM sys_organization o
WHERE o.deleted = 0
AND o.organization_name <> ''
AND ( (o.organization_code IS NOT NULL AND o.organization_code <> '')
OR EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.college_id = o.organization_id) )
AND t.unit_name LIKE CONCAT('%', o.organization_name, '%')
)
WHERE t.college_id IS NULL AND t.deleted = 0
AND t.unit_name IS NOT NULL AND t.unit_name <> '';
-- gxmu_tzbcy_form.school_name(学校名称)
UPDATE gxmu_tzbcy_form t
SET college_id = (
SELECT CASE WHEN COUNT(*) = 1 THEN MIN(o.organization_id) END
FROM sys_organization o
WHERE o.deleted = 0
AND o.organization_name <> ''
AND ( (o.organization_code IS NOT NULL AND o.organization_code <> '')
OR EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.college_id = o.organization_id) )
AND t.school_name LIKE CONCAT('%', o.organization_name, '%')
)
WHERE t.college_id IS NULL AND t.deleted = 0
AND t.school_name IS NOT NULL AND t.school_name <> '';
-- gxmu_qmgc_form.school_info(学校、院系、年级、专业)
UPDATE gxmu_qmgc_form t
SET college_id = (
SELECT CASE WHEN COUNT(*) = 1 THEN MIN(o.organization_id) END
FROM sys_organization o
WHERE o.deleted = 0
AND o.organization_name <> ''
AND ( (o.organization_code IS NOT NULL AND o.organization_code <> '')
OR EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.college_id = o.organization_id) )
AND t.school_info LIKE CONCAT('%', o.organization_name, '%')
)
WHERE t.college_id IS NULL AND t.deleted = 0
AND t.school_info IS NOT NULL AND t.school_info <> '';
-- gxmu_wxxzx_project.college_grade_class(学院、年级、班别)
UPDATE gxmu_wxxzx_project t
SET college_id = (
SELECT CASE WHEN COUNT(*) = 1 THEN MIN(o.organization_id) END
FROM sys_organization o
WHERE o.deleted = 0
AND o.organization_name <> ''
AND ( (o.organization_code IS NOT NULL AND o.organization_code <> '')
OR EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.college_id = o.organization_id) )
AND t.college_grade_class LIKE CONCAT('%', o.organization_name, '%')
)
WHERE t.college_id IS NULL AND t.deleted = 0
AND t.college_grade_class IS NOT NULL AND t.college_grade_class <> '';
-- ---------------------------------------------------------------------------
-- 3a) 回填率(只读):每张表一行
-- total_rows 参与统计的行数(deleted = 0)
-- filled_rows 有学院标识的行数
-- null_rows 仍为空的行数,等于「3b 空值清单」里该 module 的行数
-- fill_rate_pct 回填率;total_rows = 0 时为 NULL(空表没有回填率)
-- 期望:4 行;total_rows = filled_rows + null_rows
-- ---------------------------------------------------------------------------
SELECT 'gxmu_sjqn' AS module, COUNT(*) AS total_rows,
SUM(college_id IS NOT NULL) AS filled_rows,
SUM(college_id IS NULL) AS null_rows,
ROUND(SUM(college_id IS NOT NULL) / NULLIF(COUNT(*), 0) * 100, 1) AS fill_rate_pct
FROM gxmu_sjqn WHERE deleted = 0
UNION ALL
SELECT 'gxmu_tzbcy_form', COUNT(*), SUM(college_id IS NOT NULL), SUM(college_id IS NULL),
ROUND(SUM(college_id IS NOT NULL) / NULLIF(COUNT(*), 0) * 100, 1)
FROM gxmu_tzbcy_form WHERE deleted = 0
UNION ALL
SELECT 'gxmu_qmgc_form', COUNT(*), SUM(college_id IS NOT NULL), SUM(college_id IS NULL),
ROUND(SUM(college_id IS NOT NULL) / NULLIF(COUNT(*), 0) * 100, 1)
FROM gxmu_qmgc_form WHERE deleted = 0
UNION ALL
SELECT 'gxmu_wxxzx_project', COUNT(*), SUM(college_id IS NOT NULL), SUM(college_id IS NULL),
ROUND(SUM(college_id IS NOT NULL) / NULLIF(COUNT(*), 0) * 100, 1)
FROM gxmu_wxxzx_project WHERE deleted = 0;
-- ---------------------------------------------------------------------------
-- 3b) 空值清单(只读):本次没能回填上学院的行,逐行列出供人工核对
-- 输出列:
-- module 哪张表
-- id 申报记录主键(回填时直接 UPDATE ... WHERE id = ?)
-- user_id 申报人账号;为空说明这条记录没绑定登录人,两条路径都走不通
-- college_text 表单里填的学院文本(sjqn.unit_name / tzbcy_form.school_name /
-- qmgc_form.school_info / wxxzx_project.college_grade_class)
-- student_college 学生档案解析出的学院名与 ID,多个用 / 分隔;
-- 为空 = 名册里没这个人或学院没解析出来,多个 = 档案里学院不唯一
-- reason 粗分原因,便于分组处理(明细仍看 student_college 与 3c)
-- 期望:4 张表的空值行都出现在这里;填完之后可按 reason 分组人工处理。
-- ⚠ 人工处理后重跑本文件即可(只填空不覆盖),不需要删数据。
-- ---------------------------------------------------------------------------
SELECT 'gxmu_sjqn' AS module, t.id, t.user_id, t.unit_name AS college_text,
(SELECT GROUP_CONCAT(DISTINCT CONCAT(o.organization_name, '(', o.organization_id, ')') SEPARATOR ' / ')
FROM gxmu_student s JOIN sys_organization o ON o.organization_id = s.college_id
WHERE s.deleted = 0 AND s.user_id = t.user_id) AS student_college,
CASE
WHEN t.user_id IS NULL THEN '无申报人'
WHEN NOT EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL)
THEN '学生档案无学院'
WHEN (SELECT COUNT(DISTINCT s.college_id) FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL) > 1
THEN '学生档案学院不唯一'
WHEN t.unit_name IS NULL OR t.unit_name = '' THEN '表单未填学院文本'
ELSE '文本未唯一匹配(见 3c)'
END AS reason
FROM gxmu_sjqn t
WHERE t.deleted = 0 AND t.college_id IS NULL
UNION ALL
SELECT 'gxmu_tzbcy_form', t.id, t.user_id, t.school_name,
(SELECT GROUP_CONCAT(DISTINCT CONCAT(o.organization_name, '(', o.organization_id, ')') SEPARATOR ' / ')
FROM gxmu_student s JOIN sys_organization o ON o.organization_id = s.college_id
WHERE s.deleted = 0 AND s.user_id = t.user_id),
CASE
WHEN t.user_id IS NULL THEN '无申报人'
WHEN NOT EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL)
THEN '学生档案无学院'
WHEN (SELECT COUNT(DISTINCT s.college_id) FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL) > 1
THEN '学生档案学院不唯一'
WHEN t.school_name IS NULL OR t.school_name = '' THEN '表单未填学院文本'
ELSE '文本未唯一匹配(见 3c)'
END
FROM gxmu_tzbcy_form t
WHERE t.deleted = 0 AND t.college_id IS NULL
UNION ALL
SELECT 'gxmu_qmgc_form', t.id, t.user_id, t.school_info,
(SELECT GROUP_CONCAT(DISTINCT CONCAT(o.organization_name, '(', o.organization_id, ')') SEPARATOR ' / ')
FROM gxmu_student s JOIN sys_organization o ON o.organization_id = s.college_id
WHERE s.deleted = 0 AND s.user_id = t.user_id),
CASE
WHEN t.user_id IS NULL THEN '无申报人'
WHEN NOT EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL)
THEN '学生档案无学院'
WHEN (SELECT COUNT(DISTINCT s.college_id) FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL) > 1
THEN '学生档案学院不唯一'
WHEN t.school_info IS NULL OR t.school_info = '' THEN '表单未填学院文本'
ELSE '文本未唯一匹配(见 3c)'
END
FROM gxmu_qmgc_form t
WHERE t.deleted = 0 AND t.college_id IS NULL
UNION ALL
SELECT 'gxmu_wxxzx_project', t.id, t.user_id, t.college_grade_class,
(SELECT GROUP_CONCAT(DISTINCT CONCAT(o.organization_name, '(', o.organization_id, ')') SEPARATOR ' / ')
FROM gxmu_student s JOIN sys_organization o ON o.organization_id = s.college_id
WHERE s.deleted = 0 AND s.user_id = t.user_id),
CASE
WHEN t.user_id IS NULL THEN '无申报人'
WHEN NOT EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL)
THEN '学生档案无学院'
WHEN (SELECT COUNT(DISTINCT s.college_id) FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL) > 1
THEN '学生档案学院不唯一'
WHEN t.college_grade_class IS NULL OR t.college_grade_class = '' THEN '表单未填学院文本'
ELSE '文本未唯一匹配(见 3c)'
END
FROM gxmu_wxxzx_project t
WHERE t.deleted = 0 AND t.college_id IS NULL;
-- ---------------------------------------------------------------------------
-- 3c) 未匹配文本一览(只读):把空值清单里的学院文本去重,看它到底命中了哪些组织名
-- matched_names 为空 = 文本里没有任何候选学院名(填错了 / 写的是简称 / 不是学院);
-- 出现 2 个以上 = 组织树里有同义节点(如「生命科学与医学工程学院」与「生命科学与医学工程」),
-- 这种按「宁可留空」的口径留给人工判断,不自动挑一个。
-- row_count 是该文本下仍未回填的行数。
-- ---------------------------------------------------------------------------
SELECT 'gxmu_sjqn' AS module, v.college_text, v.row_count,
(SELECT GROUP_CONCAT(o.organization_name ORDER BY o.organization_name SEPARATOR ' / ')
FROM sys_organization o
WHERE o.deleted = 0
AND o.organization_name <> ''
AND ( (o.organization_code IS NOT NULL AND o.organization_code <> '')
OR EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.college_id = o.organization_id) )
AND v.college_text LIKE CONCAT('%', o.organization_name, '%')) AS matched_names
FROM (SELECT unit_name AS college_text, COUNT(*) AS row_count
FROM gxmu_sjqn WHERE deleted = 0 AND college_id IS NULL
GROUP BY unit_name) v
UNION ALL
SELECT 'gxmu_tzbcy_form', v.college_text, v.row_count,
(SELECT GROUP_CONCAT(o.organization_name ORDER BY o.organization_name SEPARATOR ' / ')
FROM sys_organization o
WHERE o.deleted = 0
AND o.organization_name <> ''
AND ( (o.organization_code IS NOT NULL AND o.organization_code <> '')
OR EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.college_id = o.organization_id) )
AND v.college_text LIKE CONCAT('%', o.organization_name, '%'))
FROM (SELECT school_name AS college_text, COUNT(*) AS row_count
FROM gxmu_tzbcy_form WHERE deleted = 0 AND college_id IS NULL
GROUP BY school_name) v
UNION ALL
SELECT 'gxmu_qmgc_form', v.college_text, v.row_count,
(SELECT GROUP_CONCAT(o.organization_name ORDER BY o.organization_name SEPARATOR ' / ')
FROM sys_organization o
WHERE o.deleted = 0
AND o.organization_name <> ''
AND ( (o.organization_code IS NOT NULL AND o.organization_code <> '')
OR EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.college_id = o.organization_id) )
AND v.college_text LIKE CONCAT('%', o.organization_name, '%'))
FROM (SELECT school_info AS college_text, COUNT(*) AS row_count
FROM gxmu_qmgc_form WHERE deleted = 0 AND college_id IS NULL
GROUP BY school_info) v
UNION ALL
SELECT 'gxmu_wxxzx_project', v.college_text, v.row_count,
(SELECT GROUP_CONCAT(o.organization_name ORDER BY o.organization_name SEPARATOR ' / ')
FROM sys_organization o
WHERE o.deleted = 0
AND o.organization_name <> ''
AND ( (o.organization_code IS NOT NULL AND o.organization_code <> '')
OR EXISTS (SELECT 1 FROM gxmu_student s WHERE s.deleted = 0 AND s.college_id = o.organization_id) )
AND v.college_text LIKE CONCAT('%', o.organization_name, '%'))
FROM (SELECT college_grade_class AS college_text, COUNT(*) AS row_count
FROM gxmu_wxxzx_project WHERE deleted = 0 AND college_id IS NULL
GROUP BY college_grade_class) v;
-- ---------------------------------------------------------------------------
-- 3d) 一致性抽查(只读)
-- a/b 段期望返回空集:回填出的学院 ID 在组织表里不存在(历史脏数据 / 节点被删)或节点已软删。
-- c 段期望每张表都是 0:有 user_id 且学生档案学院唯一、却仍为空的行;
-- 非 0 说明 A 段没执行或执行顺序被打乱。
-- ---------------------------------------------------------------------------
SELECT 'gxmu_sjqn' AS module, t.id, t.college_id
FROM gxmu_sjqn t
LEFT JOIN sys_organization o ON o.organization_id = t.college_id
WHERE t.college_id IS NOT NULL AND (o.organization_id IS NULL OR o.deleted = 1)
UNION ALL
SELECT 'gxmu_tzbcy_form', t.id, t.college_id
FROM gxmu_tzbcy_form t
LEFT JOIN sys_organization o ON o.organization_id = t.college_id
WHERE t.college_id IS NOT NULL AND (o.organization_id IS NULL OR o.deleted = 1)
UNION ALL
SELECT 'gxmu_qmgc_form', t.id, t.college_id
FROM gxmu_qmgc_form t
LEFT JOIN sys_organization o ON o.organization_id = t.college_id
WHERE t.college_id IS NOT NULL AND (o.organization_id IS NULL OR o.deleted = 1)
UNION ALL
SELECT 'gxmu_wxxzx_project', t.id, t.college_id
FROM gxmu_wxxzx_project t
LEFT JOIN sys_organization o ON o.organization_id = t.college_id
WHERE t.college_id IS NOT NULL AND (o.organization_id IS NULL OR o.deleted = 1);
-- c) 应为 0 行
SELECT 'gxmu_sjqn' AS module, COUNT(*) AS unexpected_null
FROM gxmu_sjqn t
WHERE t.deleted = 0 AND t.college_id IS NULL AND t.user_id IS NOT NULL
AND (SELECT COUNT(DISTINCT s.college_id) FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL) = 1
UNION ALL
SELECT 'gxmu_tzbcy_form', COUNT(*)
FROM gxmu_tzbcy_form t
WHERE t.deleted = 0 AND t.college_id IS NULL AND t.user_id IS NOT NULL
AND (SELECT COUNT(DISTINCT s.college_id) FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL) = 1
UNION ALL
SELECT 'gxmu_qmgc_form', COUNT(*)
FROM gxmu_qmgc_form t
WHERE t.deleted = 0 AND t.college_id IS NULL AND t.user_id IS NOT NULL
AND (SELECT COUNT(DISTINCT s.college_id) FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL) = 1
UNION ALL
SELECT 'gxmu_wxxzx_project', COUNT(*)
FROM gxmu_wxxzx_project t
WHERE t.deleted = 0 AND t.college_id IS NULL AND t.user_id IS NOT NULL
AND (SELECT COUNT(DISTINCT s.college_id) FROM gxmu_student s
WHERE s.deleted = 0 AND s.user_id = t.user_id AND s.college_id IS NOT NULL) = 1;
-- ---------------------------------------------------------------------------
-- 回滚(需要时才执行;默认注释,避免整文件执行时把值清空)
-- 只清本脚本可能写过的行:把这 4 张表的 college_id 全部置回 NULL。
-- 人工修过的值也会一起清掉,所以先按文件头「快照」段留备份。
-- ---------------------------------------------------------------------------
-- UPDATE gxmu_sjqn SET college_id = NULL WHERE college_id IS NOT NULL;
-- UPDATE gxmu_tzbcy_form SET college_id = NULL WHERE college_id IS NOT NULL;
-- UPDATE gxmu_qmgc_form SET college_id = NULL WHERE college_id IS NOT NULL;
-- UPDATE gxmu_wxxzx_project SET college_id = NULL WHERE college_id IS NOT NULL;