-- ============================================================================== -- RailwaySystem 数据库 V2 回滚脚本: 002_rollback_modified_tables.sql -- 适用数据库: KingbaseES V009R003C018 (schema: public) -- 执行目标: 严格基于 000_phase05_exact_schema.sql 结构与 bak_v1_* 数据还原 13 张表 -- 事务边界: 全程在显式事务 BEGIN ... COMMIT 中执行 -- 规范要求: -- 1. 彻底摒弃 CTAS 丢失约束/默认值/触发器的不可靠方案 -- 2. 精确采用 Phase 0.5 原始 DDL 重建表结构 -- 3. 从 bak_v1_* 恢复真实数据并严格校验行数 -- ============================================================================== BEGIN; -- 步骤 1: 显式解除既有 V2 外键约束与旧外键 ALTER TABLE train_dorm_auth DROP CONSTRAINT IF EXISTS uq_dorm_auth_accomm; ALTER TABLE train_dorm_auth DROP CONSTRAINT IF EXISTS fk_dormauth_accomm; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS uq_class_report_enroll; ALTER TABLE train_class_report DROP CONSTRAINT IF EXISTS fk_report_enrollment; ALTER TABLE train_student_checkin DROP CONSTRAINT IF EXISTS uq_student_checkin_enroll_lesson; ALTER TABLE train_student_checkin DROP CONSTRAINT IF EXISTS fk_checkin_enrollment; ALTER TABLE train_student_checkin DROP CONSTRAINT IF EXISTS fk_checkin_lesson; ALTER TABLE train_student_checkin DROP CONSTRAINT IF EXISTS fk_checkin_board; ALTER TABLE train_study_duration DROP CONSTRAINT IF EXISTS fk_study_enrollment; ALTER TABLE train_study_duration DROP CONSTRAINT IF EXISTS fk_study_plancourse; ALTER TABLE train_study_duration DROP CONSTRAINT IF EXISTS fk_study_resource; ALTER TABLE train_student_portrait DROP CONSTRAINT IF EXISTS uq_student_portrait_enroll; ALTER TABLE train_student_portrait DROP CONSTRAINT IF EXISTS fk_portrait_enrollment; ALTER TABLE train_electronic_board DROP CONSTRAINT IF EXISTS fk_board_classroom; -- 步骤 2: 常规 DROP 13 张表 DROP TABLE IF EXISTS train_student_portrait; DROP TABLE IF EXISTS train_study_duration; DROP TABLE IF EXISTS train_student_checkin; DROP TABLE IF EXISTS train_class_report; DROP TABLE IF EXISTS train_dorm_auth; DROP TABLE IF EXISTS train_electronic_board; DROP TABLE IF EXISTS train_dormitory_info; DROP TABLE IF EXISTS train_class_plan; DROP TABLE IF EXISTS train_training_site; DROP TABLE IF EXISTS train_classroom_info; DROP TABLE IF EXISTS train_course; DROP TABLE IF EXISTS train_student; DROP TABLE IF EXISTS train_teacher; -- 步骤 3: 严格依据 Phase 0.5 原始 DDL 重建 13 张表物理结构 CREATE TABLE train_teacher ( t_id VARCHAR(32) NOT NULL, t_name VARCHAR(30) NOT NULL, t_gender CHAR(2), t_birth DATE, t_department VARCHAR(50) NOT NULL, t_title VARCHAR(30), t_phone VARCHAR(20), t_email VARCHAR(50), create_user VARCHAR(32) NOT NULL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(200), CONSTRAINT pk_train_teacher PRIMARY KEY (t_id) ); CREATE TABLE train_student ( s_id VARCHAR(32) NOT NULL, s_name VARCHAR(30) NOT NULL, s_gender CHAR(2), s_birth DATE, s_department VARCHAR(50) NOT NULL, s_major VARCHAR(50) NOT NULL, s_class VARCHAR(30), s_phone VARCHAR(20), create_user VARCHAR(32) NOT NULL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(200), CONSTRAINT pk_train_student PRIMARY KEY (s_id) ); CREATE TABLE train_course ( c_id VARCHAR(32) NOT NULL, c_name VARCHAR(100) NOT NULL, c_type VARCHAR(30), c_duration INTEGER, teaching_objective TEXT, course_content TEXT, attach_doc TEXT, attach_video TEXT, attach_model_link TEXT, model_resource_ids TEXT, create_user VARCHAR(32) NOT NULL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(200), CONSTRAINT pk_train_course PRIMARY KEY (c_id) ); CREATE TABLE train_classroom_info ( class_room_id VARCHAR(32) NOT NULL, room_name VARCHAR(60) NOT NULL, room_location VARCHAR(100), capacity INTEGER, room_status SMALLINT DEFAULT 1, create_user VARCHAR(32) NOT NULL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(200), CONSTRAINT pk_train_classroom_info PRIMARY KEY (class_room_id) ); CREATE TABLE train_training_site ( site_id VARCHAR(32) NOT NULL, site_name VARCHAR(80) NOT NULL, site_location VARCHAR(100), capacity INTEGER, site_device TEXT, site_status SMALLINT DEFAULT 1, create_user VARCHAR(32) NOT NULL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(200), CONSTRAINT pk_train_training_site PRIMARY KEY (site_id) ); CREATE TABLE train_class_plan ( plan_id VARCHAR(32) NOT NULL, plan_name VARCHAR(100) NOT NULL, c_id VARCHAR(32) NOT NULL, start_time TIMESTAMP NOT NULL, end_time TIMESTAMP NOT NULL, train_address VARCHAR(100), t_id VARCHAR(32) NOT NULL, recruit_num INTEGER, apply_condition TEXT, plan_status SMALLINT DEFAULT 0, create_user VARCHAR(32) NOT NULL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(200), CONSTRAINT pk_train_class_plan PRIMARY KEY (plan_id), CONSTRAINT fk_classplan_course FOREIGN KEY (c_id) REFERENCES train_course (c_id) ON DELETE NO ACTION, CONSTRAINT fk_classplan_teacher FOREIGN KEY (t_id) REFERENCES train_teacher (t_id) ON DELETE NO ACTION ); CREATE TABLE train_dormitory_info ( dorm_id VARCHAR(32) NOT NULL, dorm_building VARCHAR(50), dorm_room VARCHAR(30) NOT NULL, bed_total INTEGER, bed_used INTEGER DEFAULT 0, lock_device_sn VARCHAR(64), dorm_status SMALLINT DEFAULT 1, create_user VARCHAR(32) NOT NULL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(200), CONSTRAINT pk_train_dormitory_info PRIMARY KEY (dorm_id), CONSTRAINT uq_dorm_building_room UNIQUE (dorm_building, dorm_room) ); CREATE TABLE train_electronic_board ( board_id VARCHAR(32) NOT NULL, board_sn VARCHAR(64) NOT NULL, bind_classroom_id VARCHAR(32), bind_plan_id VARCHAR(32), board_ip VARCHAR(50), board_content VARCHAR(500), board_playmode SMALLINT DEFAULT 1, support_checkin_type VARCHAR(30), board_status SMALLINT DEFAULT 1, last_heartbeat TIMESTAMP, create_user VARCHAR(32) NOT NULL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(200), CONSTRAINT pk_train_electronic_board PRIMARY KEY (board_id), CONSTRAINT uq_board_sn UNIQUE (board_sn), CONSTRAINT fk_board_classroom FOREIGN KEY (bind_classroom_id) REFERENCES train_classroom_info (class_room_id) ON DELETE NO ACTION, CONSTRAINT fk_board_plan FOREIGN KEY (bind_plan_id) REFERENCES train_class_plan (plan_id) ON DELETE NO ACTION ); CREATE TABLE train_dorm_auth ( auth_id BIGINT GENERATED BY DEFAULT AS IDENTITY, student_id VARCHAR(32) NOT NULL, plan_id VARCHAR(32) NOT NULL, dorm_id VARCHAR(32) NOT NULL, bed_no VARCHAR(20), face_sync_status SMALLINT DEFAULT 0, auth_start TIMESTAMP, auth_end TIMESTAMP, create_user VARCHAR(32) NOT NULL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(200), CONSTRAINT pk_train_dorm_auth PRIMARY KEY (auth_id), CONSTRAINT uq_dormauth_stu_plan UNIQUE (student_id, plan_id), CONSTRAINT fk_dormauth_stu FOREIGN KEY (student_id) REFERENCES train_student (s_id) ON DELETE NO ACTION, CONSTRAINT fk_dormauth_plan FOREIGN KEY (plan_id) REFERENCES train_class_plan (plan_id) ON DELETE NO ACTION, CONSTRAINT fk_dormauth_dorm FOREIGN KEY (dorm_id) REFERENCES train_dormitory_info (dorm_id) ON DELETE NO ACTION ); CREATE TABLE train_class_report ( report_id BIGINT GENERATED BY DEFAULT AS IDENTITY, plan_id VARCHAR(32) NOT NULL, student_id VARCHAR(32) NOT NULL, report_way SMALLINT, report_device_sn VARCHAR(64), report_time TIMESTAMP, report_status SMALLINT DEFAULT 0, alloc_dorm_id VARCHAR(32), alloc_classroom_id VARCHAR(32), alloc_site_id VARCHAR(32), create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT pk_train_class_report PRIMARY KEY (report_id), CONSTRAINT uq_classreport_plan_stu UNIQUE (plan_id, student_id), CONSTRAINT fk_classreport_plan FOREIGN KEY (plan_id) REFERENCES train_class_plan (plan_id) ON DELETE NO ACTION, CONSTRAINT fk_classreport_stu FOREIGN KEY (student_id) REFERENCES train_student (s_id) ON DELETE NO ACTION, CONSTRAINT fk_classreport_dorm FOREIGN KEY (alloc_dorm_id) REFERENCES train_dormitory_info (dorm_id) ON DELETE NO ACTION, CONSTRAINT fk_classreport_classroom FOREIGN KEY (alloc_classroom_id) REFERENCES train_classroom_info (class_room_id) ON DELETE NO ACTION, CONSTRAINT fk_classreport_site FOREIGN KEY (alloc_site_id) REFERENCES train_training_site (site_id) ON DELETE NO ACTION ); CREATE TABLE train_student_checkin ( checkin_id BIGINT GENERATED BY DEFAULT AS IDENTITY, plan_id VARCHAR(32) NOT NULL, c_id VARCHAR(32) NOT NULL, student_id VARCHAR(32) NOT NULL, board_id VARCHAR(32), checkin_way SMALLINT, checkin_time TIMESTAMP, checkin_status SMALLINT, lesson_start_time TIMESTAMP, lesson_end_time TIMESTAMP, CONSTRAINT pk_train_student_checkin PRIMARY KEY (checkin_id), CONSTRAINT uq_checkin_lesson_stu UNIQUE (plan_id, c_id, student_id, lesson_start_time), CONSTRAINT fk_checkin_plan FOREIGN KEY (plan_id) REFERENCES train_class_plan (plan_id) ON DELETE NO ACTION, CONSTRAINT fk_checkin_course FOREIGN KEY (c_id) REFERENCES train_course (c_id) ON DELETE NO ACTION, CONSTRAINT fk_checkin_stu FOREIGN KEY (student_id) REFERENCES train_student (s_id) ON DELETE NO ACTION, CONSTRAINT fk_checkin_board FOREIGN KEY (board_id) REFERENCES train_electronic_board (board_id) ON DELETE NO ACTION ); CREATE TABLE train_study_duration ( dur_id BIGINT GENERATED BY DEFAULT AS IDENTITY, student_id VARCHAR(32), plan_id VARCHAR(32), c_id VARCHAR(32), device_type VARCHAR(50), start_time TIMESTAMP, end_time TIMESTAMP, study_seconds INTEGER, sync_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT pk_train_study_duration PRIMARY KEY (dur_id), CONSTRAINT fk_studydur_stu FOREIGN KEY (student_id) REFERENCES train_student (s_id) ON DELETE NO ACTION, CONSTRAINT fk_studydur_plan FOREIGN KEY (plan_id) REFERENCES train_class_plan (plan_id) ON DELETE NO ACTION, CONSTRAINT fk_studydur_course FOREIGN KEY (c_id) REFERENCES train_course (c_id) ON DELETE NO ACTION ); CREATE TABLE train_student_portrait ( portrait_id BIGINT GENERATED BY DEFAULT AS IDENTITY, student_id VARCHAR(32) NOT NULL, plan_id VARCHAR(32) NOT NULL, total_study_hour NUMERIC(8,2), avg_score NUMERIC(5,2), checkin_rate NUMERIC(5,2), label_tag TEXT, portrait_content TEXT, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT pk_train_student_portrait PRIMARY KEY (portrait_id), CONSTRAINT uq_portrait_stu_plan UNIQUE (student_id, plan_id), CONSTRAINT fk_portrait_stu FOREIGN KEY (student_id) REFERENCES train_student (s_id) ON DELETE NO ACTION, CONSTRAINT fk_portrait_plan FOREIGN KEY (plan_id) REFERENCES train_class_plan (plan_id) ON DELETE NO ACTION ); -- 步骤 4: 重建 9 个历史触发器 CREATE OR REPLACE TRIGGER trig_train_teacher_modify BEFORE UPDATE ON train_teacher FOR EACH ROW EXECUTE FUNCTION func_train_update_modifytime(); CREATE OR REPLACE TRIGGER trig_train_student_modify BEFORE UPDATE ON train_student FOR EACH ROW EXECUTE FUNCTION func_train_update_modifytime(); CREATE OR REPLACE TRIGGER trig_train_course_modify BEFORE UPDATE ON train_course FOR EACH ROW EXECUTE FUNCTION func_train_update_modifytime(); CREATE OR REPLACE TRIGGER trig_train_classroom_modify BEFORE UPDATE ON train_classroom_info FOR EACH ROW EXECUTE FUNCTION func_train_update_modifytime(); CREATE OR REPLACE TRIGGER trig_train_trainsite_modify BEFORE UPDATE ON train_training_site FOR EACH ROW EXECUTE FUNCTION func_train_update_modifytime(); CREATE OR REPLACE TRIGGER trig_train_board_modify BEFORE UPDATE ON train_electronic_board FOR EACH ROW EXECUTE FUNCTION func_train_update_modifytime(); CREATE OR REPLACE TRIGGER trig_train_dorminfo_modify BEFORE UPDATE ON train_dormitory_info FOR EACH ROW EXECUTE FUNCTION func_train_update_modifytime(); CREATE OR REPLACE TRIGGER trig_train_classplan_modify BEFORE UPDATE ON train_class_plan FOR EACH ROW EXECUTE FUNCTION func_train_update_modifytime(); CREATE OR REPLACE TRIGGER trig_train_dormauth_modify BEFORE UPDATE ON train_dorm_auth FOR EACH ROW EXECUTE FUNCTION func_train_update_modifytime(); -- 步骤 5: 从 bak_v1_* 物理快照还原数据 INSERT INTO train_teacher SELECT * FROM bak_v1_train_teacher; INSERT INTO train_student SELECT * FROM bak_v1_train_student; INSERT INTO train_course SELECT * FROM bak_v1_train_course; INSERT INTO train_classroom_info SELECT * FROM bak_v1_train_classroom_info; INSERT INTO train_training_site SELECT * FROM bak_v1_train_training_site; INSERT INTO train_class_plan SELECT * FROM bak_v1_train_class_plan; INSERT INTO train_dormitory_info SELECT * FROM bak_v1_train_dormitory_info; INSERT INTO train_electronic_board SELECT * FROM bak_v1_train_electronic_board; INSERT INTO train_dorm_auth SELECT * FROM bak_v1_train_dorm_auth; INSERT INTO train_class_report SELECT * FROM bak_v1_train_class_report; INSERT INTO train_student_checkin SELECT * FROM bak_v1_train_student_checkin; INSERT INTO train_study_duration SELECT * FROM bak_v1_train_study_duration; INSERT INTO train_student_portrait SELECT * FROM bak_v1_train_student_portrait; -- 步骤 6: 校验教师唯一数据还原结果 DO $$ DECLARE v_cnt INT; BEGIN SELECT count(*) INTO v_cnt FROM train_teacher; IF v_cnt <> 1 THEN RAISE EXCEPTION '>>> [Rollback-FATAL] 教师数据还原失败: 期望 1 行,实际为 % 行', v_cnt; END IF; RAISE NOTICE '>>> [Rollback-PASS] 13 张表结构与教师数据已严格依据 Phase 0.5 标准 DDL 恢复完毕。'; END $$; COMMIT;