-- ============================================================================== -- RailwaySystem 数据库 V2 迁移脚本: 004_rebuild_business_tables.sql -- 适用数据库: KingbaseES V009R003C018 (schema: public) -- 执行目标: 重构 5 张需彻底解耦旧关系的空业务过程表 -- 事务边界: 全程在显式事务 BEGIN ... COMMIT 中执行 -- 设计依据: RailwaySystem 数据库 V2 字段设计与 Kingbase DDL 规范 V1.0 及 Round 1 审查要求 -- 规范要求: -- 1. 校验确认各表必须为 0 行方可重建 -- 2. 显式解除旧依赖,杜绝无边界使用 CASCADE -- 3. 为 train_study_duration 增加时间有效性与单号/系统匹配 CHECK -- ============================================================================== BEGIN; -- 步骤 1: 安全阻断校验 (确保各表确为 0 行,杜绝误删未备份数据) DO $$ DECLARE v_cnt INT; BEGIN SELECT count(*) INTO v_cnt FROM train_dorm_auth; IF v_cnt > 0 THEN RAISE EXCEPTION '>>> [004-FATAL] train_dorm_auth 包含 % 行数据,禁止重建', v_cnt; END IF; SELECT count(*) INTO v_cnt FROM train_class_report; IF v_cnt > 0 THEN RAISE EXCEPTION '>>> [004-FATAL] train_class_report 包含 % 行数据,禁止重建', v_cnt; END IF; SELECT count(*) INTO v_cnt FROM train_student_checkin; IF v_cnt > 0 THEN RAISE EXCEPTION '>>> [004-FATAL] train_student_checkin 包含 % 行数据,禁止重建', v_cnt; END IF; SELECT count(*) INTO v_cnt FROM train_study_duration; IF v_cnt > 0 THEN RAISE EXCEPTION '>>> [004-FATAL] train_study_duration 包含 % 行数据,禁止重建', v_cnt; END IF; SELECT count(*) INTO v_cnt FROM train_student_portrait; IF v_cnt > 0 THEN RAISE EXCEPTION '>>> [004-FATAL] train_student_portrait 包含 % 行数据,禁止重建', v_cnt; END IF; END $$; -- 步骤 2: 卸载旧触发器 DROP TRIGGER IF EXISTS trig_train_dormauth_modify ON train_dorm_auth; -- 步骤 3: 显式卸载已知旧外键约束 (杜绝使用 CASCADE 掩盖未预期依赖) ALTER TABLE train_dorm_auth DROP CONSTRAINT IF EXISTS fk_dormauth_stu; ALTER TABLE train_dorm_auth DROP CONSTRAINT IF EXISTS fk_dormauth_plan; ALTER TABLE train_dorm_auth DROP CONSTRAINT IF EXISTS fk_dormauth_dorm; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS fk_classreport_plan; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS fk_report_plan; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS fk_classreport_stu; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS fk_report_stu; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS fk_classreport_dorm; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS fk_report_dorm; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS fk_classreport_classroom; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS fk_report_classroom; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS fk_classreport_site; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS fk_report_site; ALTER TABLE train_student_checkin DROP CONSTRAINT IF EXISTS fk_checkin_plan; ALTER TABLE train_student_checkin DROP CONSTRAINT IF EXISTS fk_checkin_course; ALTER TABLE train_student_checkin DROP CONSTRAINT IF EXISTS fk_checkin_stu; ALTER TABLE train_student_checkin DROP CONSTRAINT IF EXISTS fk_checkin_board; ALTER TABLE train_study_duration DROP CONSTRAINT IF EXISTS fk_studydur_stu; ALTER TABLE train_study_duration DROP CONSTRAINT IF EXISTS fk_duration_stu; ALTER TABLE train_study_duration DROP CONSTRAINT IF EXISTS fk_studydur_plan; ALTER TABLE train_study_duration DROP CONSTRAINT IF EXISTS fk_duration_plan; ALTER TABLE train_study_duration DROP CONSTRAINT IF EXISTS fk_studydur_course; ALTER TABLE train_study_duration DROP CONSTRAINT IF EXISTS fk_duration_course; ALTER TABLE train_student_portrait DROP CONSTRAINT IF EXISTS fk_portrait_stu; ALTER TABLE train_student_portrait DROP CONSTRAINT IF EXISTS fk_portrait_plan; -- 步骤 4: 执行安全常规 DROP TABLE (无 CASCADE) DROP TABLE IF EXISTS train_dorm_auth; DROP TABLE IF EXISTS train_class_report; DROP TABLE IF EXISTS train_student_checkin; DROP TABLE IF EXISTS train_study_duration; DROP TABLE IF EXISTS train_student_portrait; -- 步骤 5: 按照 V2 规范重建表结构 -- 5.1 门禁授权同步表 CREATE TABLE train_dorm_auth ( auth_id BIGINT GENERATED BY DEFAULT AS IDENTITY, accommodation_id BIGINT NOT NULL, auth_start TIMESTAMP, auth_end TIMESTAMP, face_sync_status SMALLINT NOT NULL DEFAULT 0, retry_count INTEGER NOT NULL DEFAULT 0, last_error VARCHAR(500), external_auth_id VARCHAR(100), last_sync_time TIMESTAMP, create_by VARCHAR(64), create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, update_by VARCHAR(64), update_time TIMESTAMP, remark VARCHAR(500), CONSTRAINT pk_train_dorm_auth PRIMARY KEY (auth_id) ); COMMENT ON TABLE train_dorm_auth IS '宿舍门禁权限下发与同步表'; COMMENT ON COLUMN train_dorm_auth.auth_id IS '门禁授权记录ID'; COMMENT ON COLUMN train_dorm_auth.accommodation_id IS '住宿安排ID (一对一关联)'; COMMENT ON COLUMN train_dorm_auth.auth_start IS '权限生效开始时间'; COMMENT ON COLUMN train_dorm_auth.auth_end IS '权限失效结束时间'; COMMENT ON COLUMN train_dorm_auth.face_sync_status IS '同步状态 (0:待下发, 1:已下发, 2:下发失败, 3:已注销)'; COMMENT ON COLUMN train_dorm_auth.retry_count IS '同步失败重试次数'; COMMENT ON COLUMN train_dorm_auth.last_error IS '最后一次下发失败错误信息'; COMMENT ON COLUMN train_dorm_auth.external_auth_id IS '外部门禁硬件系统下发唯一授权凭证ID'; COMMENT ON COLUMN train_dorm_auth.last_sync_time IS '最近一次同步请求时间'; -- 5.2 报到事件记录表 CREATE TABLE train_class_report ( report_id BIGINT GENERATED BY DEFAULT AS IDENTITY, enrollment_id BIGINT NOT NULL, report_way SMALLINT NOT NULL, report_device_sn VARCHAR(64), report_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, verify_result SMALLINT NOT NULL, verify_note VARCHAR(500), create_by VARCHAR(64), create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(500), CONSTRAINT pk_train_class_report PRIMARY KEY (report_id) ); COMMENT ON TABLE train_class_report IS '培训班学员现场报到事件表'; COMMENT ON COLUMN train_class_report.report_id IS '报到流水ID'; COMMENT ON COLUMN train_class_report.enrollment_id IS '参训档案ID (一对一关联)'; COMMENT ON COLUMN train_class_report.report_way IS '报到核验方式 (1:人脸识别, 2:身份证刷卡, 3:二维码, 4:人工录入)'; COMMENT ON COLUMN train_class_report.report_device_sn IS '核验设备硬件序列号'; COMMENT ON COLUMN train_class_report.report_time IS '报到完成时间'; COMMENT ON COLUMN train_class_report.verify_result IS '核验结果 (1:核验通过, 2:核验不匹配, 3:人工放行)'; COMMENT ON COLUMN train_class_report.verify_note IS '核验说明/异常原因'; -- 5.3 考勤签到明细表 CREATE TABLE train_student_checkin ( checkin_id BIGINT GENERATED BY DEFAULT AS IDENTITY, enrollment_id BIGINT NOT NULL, lesson_id BIGINT NOT NULL, board_id VARCHAR(32), checkin_way SMALLINT NOT NULL, sign_in_time TIMESTAMP, sign_out_time TIMESTAMP, attendance_status SMALLINT NOT NULL DEFAULT 0, manual_flag SMALLINT NOT NULL DEFAULT 0, create_by VARCHAR(64), create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, update_by VARCHAR(64), update_time TIMESTAMP, remark VARCHAR(500), CONSTRAINT pk_train_student_checkin PRIMARY KEY (checkin_id) ); COMMENT ON TABLE train_student_checkin IS '课次考勤打卡与最终考勤结果表'; COMMENT ON COLUMN train_student_checkin.checkin_id IS '考勤记录ID'; COMMENT ON COLUMN train_student_checkin.enrollment_id IS '参训档案ID'; COMMENT ON COLUMN train_student_checkin.lesson_id IS '具体教学活动课次ID'; COMMENT ON COLUMN train_student_checkin.board_id IS '打卡电子班牌ID'; COMMENT ON COLUMN train_student_checkin.checkin_way IS '打卡方式 (1:人脸, 2:刷卡, 3:扫码, 4:教师代签)'; COMMENT ON COLUMN train_student_checkin.sign_in_time IS '签到时间'; COMMENT ON COLUMN train_student_checkin.sign_out_time IS '签退时间'; COMMENT ON COLUMN train_student_checkin.attendance_status IS '考勤结论 (0:缺勤, 1:正常出勤, 2:迟到, 3:早退, 4:请假)'; COMMENT ON COLUMN train_student_checkin.manual_flag IS '是否人工补录/修正 (0:自动, 1:人工补卡)'; -- 5.4 学习时长记录表 (自主/外部系统对接) CREATE TABLE train_study_duration ( dur_id BIGINT GENERATED BY DEFAULT AS IDENTITY, enrollment_id BIGINT NOT NULL, plan_course_id BIGINT, resource_id VARCHAR(32), learning_content VARCHAR(200), source_system VARCHAR(100), source_event_id VARCHAR(100), start_time TIMESTAMP, end_time TIMESTAMP, study_seconds INTEGER NOT NULL DEFAULT 0, sync_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, create_by VARCHAR(64), create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(500), CONSTRAINT pk_train_study_duration PRIMARY KEY (dur_id), CONSTRAINT chk_study_seconds CHECK (study_seconds >= 0), CONSTRAINT chk_study_time CHECK (end_time IS NULL OR start_time IS NULL OR end_time >= start_time), CONSTRAINT chk_study_source_system CHECK (source_event_id IS NULL OR source_system IS NOT NULL) ); COMMENT ON TABLE train_study_duration IS '学员自主学习与仿真实训时长上报表'; COMMENT ON COLUMN train_study_duration.dur_id IS '学习时长记录ID'; COMMENT ON COLUMN train_study_duration.enrollment_id IS '参训档案ID'; COMMENT ON COLUMN train_study_duration.plan_course_id IS '关联培训课程ID (可选)'; COMMENT ON COLUMN train_study_duration.resource_id IS '学习资源ID (可选)'; COMMENT ON COLUMN train_study_duration.learning_content IS '学习主题/章节内容'; COMMENT ON COLUMN train_study_duration.source_system IS '上报来源系统 (如 VR仿真系统, 在线学习端)'; COMMENT ON COLUMN train_study_duration.source_event_id IS '来源系统上报事件ID (用于幂等防重)'; COMMENT ON COLUMN train_study_duration.start_time IS '学习开始时间'; COMMENT ON COLUMN train_study_duration.end_time IS '学习结束时间'; COMMENT ON COLUMN train_study_duration.study_seconds IS '有效学习时长 (秒)'; COMMENT ON COLUMN train_study_duration.sync_time IS '系统入库时间'; -- 5.5 学员参训综合画像表 CREATE TABLE train_student_portrait ( portrait_id BIGINT GENERATED BY DEFAULT AS IDENTITY, enrollment_id BIGINT NOT NULL, attendance_rate NUMERIC(5,2), theory_score NUMERIC(7,2), practical_score NUMERIC(7,2), total_study_hour NUMERIC(8,2), label_tag TEXT, portrait_content TEXT, generated_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, create_by VARCHAR(64), create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, update_by VARCHAR(64), update_time TIMESTAMP, remark VARCHAR(500), CONSTRAINT pk_train_student_portrait PRIMARY KEY (portrait_id) ); COMMENT ON TABLE train_student_portrait IS '学员参训全过程综合评估与画像表'; COMMENT ON COLUMN train_student_portrait.portrait_id IS '画像记录ID'; COMMENT ON COLUMN train_student_portrait.enrollment_id IS '参训档案ID (单期唯一画像)'; COMMENT ON COLUMN train_student_portrait.attendance_rate IS '出勤率百分比 (0~100)'; COMMENT ON COLUMN train_student_portrait.theory_score IS '理论考试综合分'; COMMENT ON COLUMN train_student_portrait.practical_score IS '实操演练综合分'; COMMENT ON COLUMN train_student_portrait.total_study_hour IS '累计在线与自主学习总学时'; COMMENT ON COLUMN train_student_portrait.label_tag IS '特征标签集合 (JSON或逗号分隔文本)'; COMMENT ON COLUMN train_student_portrait.portrait_content IS '综合评价文本/导师评语'; COMMENT ON COLUMN train_student_portrait.generated_time IS '画像生成时间'; COMMIT;