From 5b7ddd48c7e394bcac60065ecf6346e624f5c171 Mon Sep 17 00:00:00 2001 From: weicw <594098497@qq.com> Date: Tue, 3 Nov 2026 22:28:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(spec58):=204=20=E5=BC=A0=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E8=A1=A8=20college=5Fid=20=E4=B8=80=E6=AC=A1=E6=80=A7=E5=9B=9E?= =?UTF-8?q?=E5=A1=AB=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 以学生档案 gxmu_student.college_id 为准,按 user_id 回填 sjqn / tzbcy_form / qmgc_form / wxxzx_project 的 college_id;仍为空的行再用表单里的学院文本 按组织名 LIKE 兜底,只有唯一命中才写入,无法匹配留空。 - A 段学生档案主路径,优先取在校记录的学院,档案学院不唯一时留空不猜 - B 段文本兜底,候选学院 = 有平台单位号的节点 ∪ 学生档案引用过的节点 - 只填空不覆盖,可重复执行;不接定时任务 - 附回填率、空值清单、未匹配文本一览与一致性抽查(3a-3d),供人工核对 --- sql/20261110_backfill_college_id.sql | 407 +++++++++++++++++++++++++++ 1 file changed, 407 insertions(+) create mode 100644 sql/20261110_backfill_college_id.sql diff --git a/sql/20261110_backfill_college_id.sql b/sql/20261110_backfill_college_id.sql new file mode 100644 index 0000000..8ba5c48 --- /dev/null +++ b/sql/20261110_backfill_college_id.sql @@ -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;