diff --git a/src/data/bzzoiro.py b/src/data/bzzoiro.py index 8a46efc..de88e06 100644 --- a/src/data/bzzoiro.py +++ b/src/data/bzzoiro.py @@ -417,7 +417,16 @@ async def ingest_bzzoiro_standings(db, *, leagues: Iterable[str], season: str | for t in (await db.execute(stmt)).scalars(): team_map[t.name] = t + # 预加载该 league+season 已有的 standings(避免同批内重复 INSERT 导致 UniqueViolation) + existing_standings: set[int] = set() + stmt = select(Standing.team_id).where( + Standing.league_id == league.id, Standing.season == season_label, + ) + for (tid,) in (await db.execute(stmt)).all(): + existing_standings.add(tid) + now = datetime.now(timezone.utc) + seen_teams: set[int] = set() # 同批内去重:同一 team 只处理一次 for r in rows: team_name = normalize_name(str(r.get("team_name", ""))) if not team_name: @@ -430,6 +439,11 @@ async def ingest_bzzoiro_standings(db, *, leagues: Iterable[str], season: str | team_map[team_name] = team league_r["teams_created"] += 1 + # 同批内同一 team 仅处理第一次 + if team.id in seen_teams: + continue + seen_teams.add(team.id) + zone = r.get("zone") or {} values = dict( position=_to_int_or_none(r.get("position")) or 0, @@ -449,20 +463,22 @@ async def ingest_bzzoiro_standings(db, *, leagues: Iterable[str], season: str | retrieved_at=now, ) - stmt = select(Standing).where( - Standing.league_id == league.id, - Standing.season == season_label, - Standing.team_id == team.id, - ) - standing = (await db.execute(stmt)).scalar_one_or_none() - if standing is None: - standing = Standing( - league_id=league.id, season=season_label, team_id=team.id, **values + if team.id in existing_standings: + # 已有 → 仍需 UPDATE:回查对象(少量,可接受) + stmt = select(Standing).where( + Standing.league_id == league.id, + Standing.season == season_label, + Standing.team_id == team.id, ) - db.add(standing) + standing = (await db.execute(stmt)).scalar_one_or_none() + if standing: + for k, v in values.items(): + setattr(standing, k, v) else: - for k, v in values.items(): - setattr(standing, k, v) + db.add(Standing( + league_id=league.id, season=season_label, team_id=team.id, **values, + )) + existing_standings.add(team.id) # 防止同批内重复 league_r["upserted"] += 1 league_r["rows"] = len(rows)