"""为 predictions 表添加 match_id+provider+model 唯一约束 Revision ID: 0007_predictions_unique_constraint Revises: 0007_injuries_constraint_naming_align Create Date: 2026-09-16 背景(见代码审查报告 P1-6): 同一 match_id + provider + model 组合不应产生重复预测。 当前缺少数据库级唯一约束,回测多次运行或并发采集可能产生重复记录, 导致统计偏差。 先清理已存在的重复记录(保留最早创建的那条),再添加唯一约束。 """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision: str = '0007_predictions_unique_constraint' down_revision: Union[str, None] = '0007_injuries_constraint_naming_align' branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # 1. 清理已存在的重复记录(保留 id 最小的) op.execute( """ DELETE FROM predictions WHERE id NOT IN ( SELECT MIN(id) FROM predictions GROUP BY match_id, provider, model ) AND match_id IN ( SELECT match_id FROM predictions GROUP BY match_id, provider, model HAVING COUNT(*) > 1 ) """ ) # 2. 添加唯一约束 op.create_unique_constraint( "uq_predictions_match_provider_model", "predictions", ["match_id", "provider", "model"], ) def downgrade() -> None: op.drop_constraint( "uq_predictions_match_provider_model", "predictions", type_="unique", )