Files
ruoyi-vue-pro/sql/mysql/education/005-education-wrong-question.sql

155 lines
9.2 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- =============================================
-- Education 模块 — 错题本 DDL
-- Ticket #9: 错题自动收集、复习练习创建
-- Migration: 005
-- Prerequisites: 004-education-submit-report.sql (report + detail tables)
-- =============================================
-- =============================================
-- Preconditions
-- =============================================
-- Operator is expected to verify:
-- SELECT COUNT(*) FROM information_schema.tables
-- WHERE table_schema = DATABASE()
-- AND table_name IN ('education_wrong_question',
-- 'education_wrong_question_idempotency');
-- Result MUST be 0 before executing this migration.
--
-- Verify prerequisite tables exist:
-- SELECT COUNT(*) FROM information_schema.tables
-- WHERE table_schema = DATABASE()
-- AND table_name IN ('education_practice_report',
-- 'education_practice_report_detail');
-- Result MUST be 2.
-- =============================================
-- PracticeReportDetailDO: add options snapshot column
-- =============================================
-- PracticeReportDetailDO: add content_version + options snapshot columns
-- =============================================
-- Purpose: At submit time, snapshot question content version and options
-- (without isCorrect) so wrong-question book and review sessions have
-- stable display data. The options are already stripped of isCorrect
-- by the submit flow.
ALTER TABLE `education_practice_report_detail`
ADD COLUMN `content_version` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '题目内容版本快照',
ADD COLUMN `options` TEXT DEFAULT NULL COMMENT '选项快照 JSON不含 isCorrect';
-- =============================================
-- PracticeSessionDO: add review fingerprint column
-- =============================================
-- Purpose: Persist the canonical fingerprint of wrong-question IDs used
-- to create a review session. On idempotent replay, the fingerprint
-- is compared: same tenant+clientSessionId+sameUser+sortedIDs match
-- returns the existing session; different ID set returns
-- SESSION_IDEMPOTENCY_MISMATCH.
ALTER TABLE `education_practice_session`
ADD COLUMN `review_fingerprint` VARCHAR(64) DEFAULT NULL COMMENT '复习会话题目指纹SHA-256 of sorted unique wrongQuestionIds';
-- 错题表
-- =============================================
-- Purpose: Persistent wrong-question book per student.
-- Each (tenant, user, question) is a unique entry.
-- Repeated wrong answers on the SAME question increment wrong_count
-- and update last_wrong_time. The idempotency guard table ensures
-- each (tenant, user, question, report) can upsert at most once.
--
-- master_status values: 'PENDING' (default) | 'MASTERED'
-- Marking mastered retains the full history and count; it does NOT
-- delete or archive the record. Students can optionally un-master.
--
-- Snapshot fields (stem, type, difficulty, options, content_version):
-- populated from the latest report detail that touched this question.
-- These are for listing/detail display without joining report details.
--
-- latest_correct_answer, latest_explanation:
-- also from the latest report detail; available for detail display
-- post-submit (not exposed in review session creation pre-submit).
--
-- Indexes:
-- uk_tenant_user_question — per-tenant, per-user, per-question uniqueness.
-- INSERT ... ON DUPLICATE KEY UPDATE is the primary write path.
-- idx_tenant_user_status — covers filtered list queries (page with status filter).
-- idx_tenant_user_last_wrong — covers time-sorted listing.
CREATE TABLE `education_wrong_question` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` BIGINT NOT NULL COMMENT '租户编号',
`user_id` BIGINT NOT NULL COMMENT '学生用户编号',
`question_id` VARCHAR(64) NOT NULL COMMENT '原始题目 ID',
-- snapshot fields for listing / detail (from latest report detail)
`stem` TEXT NOT NULL COMMENT '题干快照(最新)',
`type` VARCHAR(32) NOT NULL COMMENT '题型快照',
`difficulty` VARCHAR(32) DEFAULT NULL COMMENT '难度快照',
`options` JSON NOT NULL COMMENT '选项快照 JSON不含 isCorrect',
`content_version` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '题目内容版本',
`latest_correct_answer` TEXT DEFAULT NULL COMMENT '正确答案快照(最新,供详情展示)',
`latest_explanation` TEXT DEFAULT NULL COMMENT '解析快照(最新,供详情展示)',
-- timing & count
`first_wrong_time` DATETIME NOT NULL COMMENT '首次错误时间',
`last_wrong_time` DATETIME NOT NULL COMMENT '最近错误时间',
`wrong_count` INT NOT NULL DEFAULT 1 COMMENT '累计错误次数',
-- mastery
`master_status` VARCHAR(20) NOT NULL DEFAULT 'PENDING'
COMMENT '掌握状态PENDING-待掌握, MASTERED-已掌握',
`mastered_time` DATETIME DEFAULT NULL COMMENT '标记掌握时间',
-- provenance
`last_report_id` BIGINT DEFAULT NULL COMMENT '最近关联的报告 ID',
`last_session_id` BIGINT DEFAULT NULL COMMENT '最近关联的会话 ID',
-- audit
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_user_question` (`tenant_id`, `user_id`, `question_id`),
KEY `idx_tenant_user_status` (`tenant_id`, `user_id`, `master_status`),
KEY `idx_tenant_user_last_wrong` (`tenant_id`, `user_id`, `last_wrong_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='教育-错题本';
-- =============================================
-- 错题流水幂等表
-- =============================================
-- Purpose: Ensure each (tenant, user, question, report) upserts the
-- wrong-question book exactly once. The submitSession transaction
-- INSERT IGNOREs into this table BEFORE the wrong question upsert;
-- a duplicate means this report already contributed to the count.
-- This guards against:
-- - Replayed submit (idempotent resubmit) double-counting
-- - Concurrent submit races where both threads evaluate the
-- same report details
--
-- Indexes:
-- uk_tenant_user_question_report — per (tenant, user, question, report) uniqueness.
-- INSERT IGNORE provides the idempotency guard BEFORE upserting.
-- wrong_question_id is filled after upsert for audit purposes.
-- idx_report — fast lookup by report for audit/debug.
CREATE TABLE `education_wrong_question_idempotency` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` BIGINT NOT NULL COMMENT '租户编号',
`user_id` BIGINT NOT NULL COMMENT '学生用户编号',
`wrong_question_id` BIGINT DEFAULT NULL COMMENT '错题记录 IDupsert 后填充)',
`report_id` BIGINT NOT NULL COMMENT '报告 ID',
`question_id` VARCHAR(64) NOT NULL COMMENT '题目 ID',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_user_question_report` (`tenant_id`, `user_id`, `question_id`, `report_id`),
KEY `idx_report` (`report_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='教育-错题流水幂等';
-- =============================================
-- Post-migration verification queries
-- =============================================
-- Verify new tables exist:
-- SHOW CREATE TABLE education_wrong_question;
-- SHOW CREATE TABLE education_wrong_question_idempotency;
-- Verify unique keys are enforced:
-- SHOW INDEX FROM education_wrong_question WHERE Key_name = 'uk_tenant_user_question';
-- SHOW INDEX FROM education_wrong_question_idempotency WHERE Key_name = 'uk_tenant_user_question_report';
-- Verify no orphan data (should be 0 after fresh migration):
-- SELECT COUNT(*) FROM education_wrong_question;
-- SELECT COUNT(*) FROM education_wrong_question_idempotency;