-- xuchao: 修复历史迁移缺口。早期这些表是用 drizzle push/手工 DDL 建进生产的, -- 仓库里一直没有对应迁移,导致全新数据库建不出这些表。本迁移全部幂等: -- 表已存在则 CREATE TABLE IF NOT EXISTS 跳过,生产库重复执行无副作用。 CREATE TABLE IF NOT EXISTS `grammar_point` ( `id` bigint AUTO_INCREMENT NOT NULL, `point_id` varchar(191) NOT NULL, `level` varchar(20) NOT NULL, `level_name` varchar(50) NOT NULL, `title` varchar(200) NOT NULL, `difficulty` int NOT NULL DEFAULT 1, `summary` text, `prereq` text, `md` mediumtext NOT NULL, `seq` int NOT NULL, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT `grammar_point_id` PRIMARY KEY(`id`), CONSTRAINT `uq_grammar_point_id` UNIQUE(`point_id`) ); --> statement-breakpoint CREATE TABLE IF NOT EXISTS `weekly_test` ( `id` bigint AUTO_INCREMENT NOT NULL, `child_user_id` bigint NOT NULL, `week_key` varchar(12) NOT NULL, `score` int, `correct` int, `total` int, `passed` boolean NOT NULL DEFAULT false, `questions` mediumtext, `taken_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT `weekly_test_id` PRIMARY KEY(`id`), CONSTRAINT `uq_weekly_child_week` UNIQUE(`child_user_id`,`week_key`), CONSTRAINT `fk_wt_child` FOREIGN KEY (`child_user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action ); --> statement-breakpoint CREATE TABLE IF NOT EXISTS `word_progress` ( `id` bigint AUTO_INCREMENT NOT NULL, `child_user_id` bigint NOT NULL, `day` int NOT NULL, `learned` mediumtext, `score` int, `passed` boolean NOT NULL DEFAULT false, `completed_at` datetime, CONSTRAINT `word_progress_id` PRIMARY KEY(`id`), CONSTRAINT `uq_word_child_day` UNIQUE(`child_user_id`,`day`), CONSTRAINT `fk_wp_child` FOREIGN KEY (`child_user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action ); --> statement-breakpoint CREATE TABLE IF NOT EXISTS `word_recording` ( `id` bigint AUTO_INCREMENT NOT NULL, `child_user_id` bigint NOT NULL, `word` varchar(60) NOT NULL, `day` int, `oss_key` varchar(300) NOT NULL, `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT `word_recording_id` PRIMARY KEY(`id`), KEY `idx_rec_child` (`child_user_id`), CONSTRAINT `fk_wr_child` FOREIGN KEY (`child_user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action ); --> statement-breakpoint CREATE TABLE IF NOT EXISTS `wrong_book` ( `id` bigint AUTO_INCREMENT NOT NULL, `child_user_id` bigint NOT NULL, `source_type` varchar(10) NOT NULL, `source_id` varchar(60) NOT NULL, `source_title` varchar(200), `question` mediumtext NOT NULL, `user_answer` mediumtext, `correct_answer` mediumtext, `mastered` boolean NOT NULL DEFAULT false, `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT `wrong_book_id` PRIMARY KEY(`id`), KEY `idx_wrong_child` (`child_user_id`,`mastered`), CONSTRAINT `fk_wb_child` FOREIGN KEY (`child_user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action ); --> statement-breakpoint -- grammar_progress:0002 误用 seq 列建表,生产实际是 point_id。仅在缺 point_id 时转换。 -- 顺序关键:先加 point_id 与 uq_grammar_child_point(child_user_id 为最左前缀,可承接外键), -- 之后才能安全删除被外键依赖的旧索引 uq_grammar_child_seq,全程不动外键本身。 SET @gp_has_point = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'grammar_progress' AND column_name = 'point_id'); --> statement-breakpoint SET @ddl = IF(@gp_has_point = 0, 'ALTER TABLE `grammar_progress` ADD COLUMN `point_id` varchar(191) NOT NULL', 'SELECT 1'); --> statement-breakpoint PREPARE stmt FROM @ddl; --> statement-breakpoint EXECUTE stmt; --> statement-breakpoint DEALLOCATE PREPARE stmt; --> statement-breakpoint SET @gp_has_point_idx = (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'grammar_progress' AND index_name = 'uq_grammar_child_point'); --> statement-breakpoint SET @ddl = IF(@gp_has_point_idx = 0, 'ALTER TABLE `grammar_progress` ADD CONSTRAINT `uq_grammar_child_point` UNIQUE (`child_user_id`,`point_id`)', 'SELECT 1'); --> statement-breakpoint PREPARE stmt FROM @ddl; --> statement-breakpoint EXECUTE stmt; --> statement-breakpoint DEALLOCATE PREPARE stmt; --> statement-breakpoint SET @gp_has_seq_idx = (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'grammar_progress' AND index_name = 'uq_grammar_child_seq'); --> statement-breakpoint SET @ddl = IF(@gp_has_seq_idx > 0, 'ALTER TABLE `grammar_progress` DROP INDEX `uq_grammar_child_seq`', 'SELECT 1'); --> statement-breakpoint PREPARE stmt FROM @ddl; --> statement-breakpoint EXECUTE stmt; --> statement-breakpoint DEALLOCATE PREPARE stmt; --> statement-breakpoint SET @gp_has_seq = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'grammar_progress' AND column_name = 'seq'); --> statement-breakpoint SET @ddl = IF(@gp_has_seq > 0, 'ALTER TABLE `grammar_progress` DROP COLUMN `seq`', 'SELECT 1'); --> statement-breakpoint PREPARE stmt FROM @ddl; --> statement-breakpoint EXECUTE stmt; --> statement-breakpoint DEALLOCATE PREPARE stmt;