Skip to main content
The fetch_games_teamwins function retrieves team-level game logs for a given NBA season using nba_api and persists them to a local SQLite database (nba_stats.db). Each run is safe to repeat — rows are upserted, so existing records are overwritten rather than duplicated.

Function signature

fetch_games_teamwins(season="2025-2026")

Parameters

ParameterTypeDefaultDescription
seasonstr"2025-2026"NBA season string passed to nba_api. The source default uses "YYYY-YYYY" format (e.g. "2025-2026"), but nba_api also accepts abbreviated formats like "2025-26".

Usage

from Data.fetch_games import fetch_games_teamwins

# Fetch the current season (default: "2025-2026")
fetch_games_teamwins()

# Fetch a specific past season
fetch_games_teamwins(season="2024-2025")

Data source

Game logs are fetched from the NBA Stats API via nba_api.stats.endpoints.leaguegamelog, requesting regular season data at the team level (player_or_team_abbreviation="T").
from nba_api.stats.endpoints import leaguegamelog

df = leaguegamelog.LeagueGameLog(
    season=season,
    season_type_all_star="Regular Season",
    player_or_team_abbreviation="T"
).get_data_frames()[0]

Self-join logic

The raw game log contains one row per team per game. To attach opponent stats to each row, the function performs a self-join on GAME_ID:
merged = df.merge(
    df,
    on="GAME_ID",
    suffixes=("_team", "_opp")
)

# Remove rows where a team is matched against itself
merged = merged[merged["TEAM_ID_team"] != merged["TEAM_ID_opp"]].copy()
This means every game produces two rows — one from each team’s perspective. For a game between Team A and Team B:
  • Row 1: team = A, opponent = B, with A’s stats as team_* and B’s stats as opponent_*
  • Row 2: team = B, opponent = A, with B’s stats as team_* and A’s stats as opponent_*

The home field

The home column is derived from the MATCHUP string returned by the API:
merged["home"] = merged["MATCHUP_team"].apply(lambda x: 1 if "vs." in x else 0)
ValueMeaningExample matchup string
1Home game"BOS vs. MIA"
0Away game"MIA @ BOS"

games table schema

The function creates the games table if it does not already exist:
CREATE TABLE IF NOT EXISTS games (
    game_id           TEXT,
    game_date         TEXT,
    team_id           INTEGER,
    team              TEXT,
    opponent          TEXT,
    team_points       INTEGER,
    opponent_points   INTEGER,
    team_reb          INTEGER,
    opponent_reb      INTEGER,
    team_ast          INTEGER,
    opponent_ast      INTEGER,
    home              INTEGER,
    win               INTEGER,
    PRIMARY KEY (game_id, team_id)
)
ColumnTypeDescription
game_idTEXTUnique NBA game identifier.
game_dateTEXTDate of the game.
team_idINTEGERNBA team ID for the team row.
teamTEXTTeam abbreviation, e.g. "BOS".
opponentTEXTOpponent abbreviation, e.g. "MIA".
team_pointsINTEGERPoints scored by the team.
opponent_pointsINTEGERPoints scored by the opponent.
team_rebINTEGERRebounds by the team.
opponent_rebINTEGERRebounds by the opponent.
team_astINTEGERAssists by the team.
opponent_astINTEGERAssists by the opponent.
homeINTEGER1 if the team played at home, 0 if away.
winINTEGER1 if the team won, 0 if they lost.
The primary key is (game_id, team_id), which uniquely identifies each team’s perspective on a game.

Idempotent writes

Rows are written with INSERT OR REPLACE, so running the function multiple times for the same season will overwrite existing records rather than create duplicates:
cursor.execute("""
INSERT OR REPLACE INTO games (
    game_id, game_date, team_id, team, opponent,
    team_points, opponent_points,
    team_reb, opponent_reb,
    team_ast, opponent_ast,
    home, win
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""", (...))
The database file nba_stats.db is created in the same directory as fetch_games.py. Make sure the Data/ directory is writable before running the function.

Build docs developers (and LLMs) love