complete app
test / test (push) Successful in 9s

This commit is contained in:
2026-09-17 17:39:22 -05:00
parent 4d633a39be
commit 3d5de1dc3e
84 changed files with 24229 additions and 0 deletions
@@ -0,0 +1,58 @@
---
version: 2
models:
- name: int_player_performance
description: "Unified model containing basic and advanced stats for each player in every game. Grain: one row per player per game."
tests:
- dbt_utils.unique_combination_of_columns:
combination_of_columns:
- game_id
- player_id
columns:
- name: game_id
tests:
- not_null
- name: player_id
tests:
- not_null
- name: int_team_performance
description: "Unified model containing basic and advanced stats for each team in every game. Grain: one row per team per game."
tests:
- dbt_utils.unique_combination_of_columns:
combination_of_columns:
- game_id
- team
columns:
- name: game_id
tests:
- not_null
- name: team
tests:
- not_null
- name: int_games_enriched
description: "Game-level model enriched with detailed performance stats for both the home and visitor teams. Grain: one row per game."
columns:
- name: game_id
tests:
- unique
- not_null
- name: int_player_shots_enriched
description: >
Unified shot-level dataset combining field goal attempts (from shot charts)
with free throw attempts (derived from stg_player_game_basic_stats).
Grain: one row per shot attempt (FG or FT).
columns:
- name: shot_id
tests:
- not_null
- name: player_id
tests:
- not_null
- name: shot_source
tests:
- not_null
- accepted_values:
values: ['shot_chart', 'box_score_ft']
@@ -0,0 +1,81 @@
{{
config(
materialized='table',
schema='intermediate',
tags=["intermediate"]
)
}}
WITH games AS (
SELECT
g.*,
home_map.team_abbr AS home_team_abbr,
visitor_map.team_abbr AS visitor_team_abbr,
winning_map.team_abbr AS winning_team_abbr
FROM {{ ref('stg_games') }} AS g
LEFT JOIN {{ ref('team_maps') }} AS home_map ON g.home_team = home_map.full_name
LEFT JOIN {{ ref('team_maps') }} AS visitor_map ON g.visitor_team = visitor_map.full_name
LEFT JOIN {{ ref('team_maps') }} AS winning_map ON g.winning_team = winning_map.full_name
WHERE (g.season_start_year >= home_map.start_year AND g.season_start_year < home_map.end_year)
AND (g.season_start_year >= visitor_map.start_year AND g.season_start_year < visitor_map.end_year)
AND (g.season_start_year >= winning_map.start_year AND g.season_start_year < winning_map.end_year)
),
arena_locations AS (
SELECT arena_name, arena_city
FROM (
SELECT
arena_name,
city AS arena_city,
ROW_NUMBER() OVER (PARTITION BY arena_name ORDER BY city) as rn
FROM {{ ref('arena_maps') }}
) AS sub
WHERE rn = 1
),
team_performance AS (
SELECT * FROM {{ ref('int_team_performance') }}
),
final AS (
SELECT
g.game_id,
g.game_date,
g.season_start_year,
g.is_playoff,
g.arena,
al.arena_city,
g.home_team_abbr AS home_team,
g.visitor_team_abbr AS visitor_team,
g.winning_team_abbr AS winning_team,
g.home_points,
g.visitor_points,
g.point_differential,
g.total_points,
g.is_overtime,
home_stats.offensive_rating AS home_offensive_rating,
home_stats.defensive_rating AS home_defensive_rating,
home_stats.net_rating AS home_net_rating,
home_stats.pace AS home_pace,
home_stats.effective_fg_pct AS home_effective_fg_pct,
home_stats.turnover_rate AS home_turnover_rate,
home_stats.offensive_tier AS home_offensive_tier,
home_stats.defensive_tier AS home_defensive_tier,
visitor_stats.offensive_rating AS visitor_offensive_rating,
visitor_stats.defensive_rating AS visitor_defensive_rating,
visitor_stats.net_rating AS visitor_net_rating,
visitor_stats.pace AS visitor_pace,
visitor_stats.effective_fg_pct AS visitor_effective_fg_pct,
visitor_stats.turnover_rate AS visitor_turnover_rate,
visitor_stats.offensive_tier AS visitor_offensive_tier,
visitor_stats.defensive_tier AS visitor_defensive_tier,
(home_stats.pace + visitor_stats.pace) / 2 AS matchup_pace
FROM games g
LEFT JOIN arena_locations al ON g.arena = al.arena_name
LEFT JOIN team_performance AS home_stats
ON g.game_id = home_stats.game_id AND g.home_team_abbr = home_stats.team
LEFT JOIN team_performance AS visitor_stats
ON g.game_id = visitor_stats.game_id AND g.visitor_team_abbr = visitor_stats.team
)
SELECT * FROM final
@@ -0,0 +1,97 @@
{{
config(
materialized='table',
schema='intermediate',
tags=["intermediate"]
)
}}
WITH basic_stats AS (
SELECT
s.*,
map.team_abbr AS team_conformed
FROM {{ ref('stg_player_game_basic_stats') }} AS s
LEFT JOIN {{ ref('team_maps') }} AS map
ON s.team = map.team_abbr
LEFT JOIN {{ ref('stg_games') }} AS g
ON s.game_id = g.game_id
WHERE did_play = TRUE
AND (g.season_start_year >= map.start_year AND g.season_start_year < map.end_year)
),
adv_stats AS (
SELECT
s.*,
map.team_abbr AS team_conformed
FROM {{ ref('stg_player_game_adv_stats_extended') }} AS s
LEFT JOIN {{ ref('team_maps') }} AS map
ON s.team = map.team_abbr
LEFT JOIN {{ ref('stg_games') }} AS g
ON s.game_id = g.game_id
WHERE (g.season_start_year >= map.start_year AND g.season_start_year < map.end_year)
),
games AS (
SELECT
g.game_id,
g.game_date,
g.season_start_year,
g.is_playoff,
home_map.team_abbr AS home_team_abbr,
winning_map.team_abbr AS winning_team_abbr
FROM {{ ref('stg_games') }} g
LEFT JOIN {{ ref('team_maps') }} AS home_map ON g.home_team = home_map.full_name
LEFT JOIN {{ ref('team_maps') }} AS winning_map ON g.winning_team = winning_map.full_name
WHERE (g.season_start_year >= home_map.start_year AND g.season_start_year < home_map.end_year)
AND (g.season_start_year >= winning_map.start_year AND g.season_start_year < winning_map.end_year)
),
final AS (
SELECT
b.game_id,
b.player_id,
b.player_name,
b.team_conformed AS team,
g.game_date,
g.season_start_year,
g.is_playoff,
CASE WHEN b.team_conformed = g.winning_team_abbr THEN 'W' ELSE 'L' END AS game_result,
CASE WHEN b.team_conformed = g.home_team_abbr THEN 'HOME' ELSE 'AWAY' END AS team_location,
b.minutes_played,
b.points,
b.assists,
b.total_rebounds,
b.steals,
b.blocks,
b.turnovers,
b.plus_minus,
a.net_rating,
a.box_plus_minus,
b.field_goals_made,
b.field_goals_attempted,
b.field_goal_pct,
b.three_pointers_made,
b.three_pointers_attempted,
b.three_point_pct,
a.true_shooting_pct,
a.effective_fg_pct,
a.usage_pct,
a.offensive_rating,
a.defensive_rating,
a.usage_tier,
a.impact_tier,
a.shooting_efficiency_tier,
a.minutes_based_role,
b.is_double_double,
b.is_triple_double,
a.is_versatile,
a.is_defensive_specialist,
a.is_three_and_d
FROM basic_stats AS b
LEFT JOIN adv_stats AS a
ON b.game_id = a.game_id AND b.player_id = a.player_id
LEFT JOIN games AS g
ON b.game_id = g.game_id
)
SELECT * FROM final
@@ -0,0 +1,214 @@
{{
config(
materialized='table',
schema='intermediate',
tags=["intermediate"]
)
}}
WITH shot_charts AS (
SELECT * FROM {{ ref('stg_player_shot_charts') }}
),
games AS (
SELECT
g.game_id,
g.game_date,
g.season_start_year,
g.is_playoff,
g.arena,
g.home_points,
g.visitor_points,
g.point_differential,
g.is_overtime,
home_map.team_abbr AS home_team_abbr,
visitor_map.team_abbr AS visitor_team_abbr,
winning_map.team_abbr AS winning_team_abbr
FROM {{ ref('stg_games') }} AS g
LEFT JOIN {{ ref('team_maps') }} AS home_map ON g.home_team = home_map.full_name
LEFT JOIN {{ ref('team_maps') }} AS visitor_map ON g.visitor_team = visitor_map.full_name
LEFT JOIN {{ ref('team_maps') }} AS winning_map ON g.winning_team = winning_map.full_name
WHERE (g.season_start_year >= home_map.start_year AND g.season_start_year < home_map.end_year)
AND (g.season_start_year >= visitor_map.start_year AND g.season_start_year < visitor_map.end_year)
AND (g.season_start_year >= winning_map.start_year AND g.season_start_year < winning_map.end_year)
),
shots_conformed AS (
SELECT
sc.*,
COALESCE(tm.team_abbr, sc.team_abbr_raw) AS team_conformed,
COALESCE(opp.team_abbr, sc.opponent_abbr_raw) AS opponent_conformed
FROM shot_charts AS sc
LEFT JOIN {{ ref('team_maps') }} AS tm
ON sc.team_abbr_raw = tm.team_abbr
AND sc.season_start_year >= tm.start_year
AND sc.season_start_year < tm.end_year
LEFT JOIN {{ ref('team_maps') }} AS opp
ON sc.opponent_abbr_raw = opp.team_abbr
AND sc.season_start_year >= opp.start_year
AND sc.season_start_year < opp.end_year
),
shots_with_game AS (
SELECT
sc.*,
g.game_id,
g.is_playoff,
g.arena,
g.is_overtime AS game_had_overtime,
CASE
WHEN sc.team_conformed = g.home_team_abbr THEN 'HOME'
WHEN sc.team_conformed = g.visitor_team_abbr THEN 'AWAY'
ELSE NULL
END AS team_location,
CASE
WHEN sc.team_conformed = g.winning_team_abbr THEN 'W'
ELSE 'L'
END AS game_result
FROM shots_conformed AS sc
LEFT JOIN games AS g
ON CAST(sc.game_date AS DATE) = CAST(g.game_date AS DATE)
AND (
(sc.team_conformed = g.home_team_abbr AND sc.opponent_conformed = g.visitor_team_abbr)
OR
(sc.team_conformed = g.visitor_team_abbr AND sc.opponent_conformed = g.home_team_abbr)
)
),
fg_shots AS (
SELECT
shot_id,
game_id,
player_id,
team_conformed AS team,
opponent_conformed AS opponent,
game_date,
game_date_raw,
season_start_year,
is_playoff,
team_location,
game_result,
game_had_overtime,
quarter_raw,
quarter_number,
is_overtime_shot,
time_remaining_raw,
seconds_remaining_in_quarter,
shot_x_coordinate,
shot_y_coordinate,
is_made,
shot_made_flag,
shot_missed_flag,
shot_type_raw,
shot_point_value,
is_three_pointer,
is_free_throw,
distance_ft,
shot_distance_zone,
points_generated,
team_had_lead,
team_score_at_shot,
opponent_score_at_shot,
score_margin_at_shot,
is_clutch_shot,
CASE WHEN game_id IS NOT NULL THEN TRUE ELSE FALSE END AS has_game_match,
'shot_chart' AS shot_source,
created_at,
updated_at,
dbt_loaded_at
FROM shots_with_game
),
-- Free throw expansion using DuckDB's generate_series + UNNEST
matched_player_games AS (
SELECT DISTINCT
game_id, player_id, team, opponent, game_date, game_date_raw,
season_start_year, is_playoff, team_location, game_result, game_had_overtime
FROM fg_shots
WHERE has_game_match = TRUE
),
ft_source AS (
SELECT
mpg.*,
bs.free_throws_made,
bs.free_throws_attempted
FROM matched_player_games AS mpg
INNER JOIN {{ ref('stg_player_game_basic_stats') }} AS bs
ON mpg.game_id = bs.game_id AND mpg.player_id = bs.player_id
WHERE bs.did_play = TRUE AND bs.free_throws_attempted > 0
),
ft_made_expanded AS (
SELECT ft.*, n.n AS ft_seq, TRUE AS ft_is_made
FROM ft_source AS ft
CROSS JOIN LATERAL (SELECT UNNEST(generate_series(1, GREATEST(ft.free_throws_made, 0))) AS n) AS n
WHERE ft.free_throws_made > 0
),
ft_missed_expanded AS (
SELECT ft.*, n.n AS ft_seq, FALSE AS ft_is_made
FROM ft_source AS ft
CROSS JOIN LATERAL (SELECT UNNEST(generate_series(1, GREATEST(ft.free_throws_attempted - ft.free_throws_made, 0))) AS n) AS n
WHERE ft.free_throws_attempted > ft.free_throws_made
),
ft_shots AS (
SELECT
-(ABS(hash(
ft.game_id || '|' || ft.player_id || '|FT_'
|| CASE WHEN ft.ft_is_made THEN 'MADE' ELSE 'MISS' END
|| '|' || CAST(ft.ft_seq AS TEXT)
)) % 9223372036854775807 + 1) AS shot_id,
ft.game_id,
ft.player_id,
ft.team,
ft.opponent,
ft.game_date,
ft.game_date_raw,
ft.season_start_year,
ft.is_playoff,
ft.team_location,
ft.game_result,
ft.game_had_overtime,
'Free Throw' AS quarter_raw,
0 AS quarter_number,
FALSE AS is_overtime_shot,
NULL AS time_remaining_raw,
NULL::INT AS seconds_remaining_in_quarter,
NULL::BIGINT AS shot_x_coordinate,
NULL::BIGINT AS shot_y_coordinate,
ft.ft_is_made AS is_made,
CASE WHEN ft.ft_is_made THEN 1 ELSE 0 END AS shot_made_flag,
CASE WHEN ft.ft_is_made THEN 0 ELSE 1 END AS shot_missed_flag,
'free-throw' AS shot_type_raw,
1 AS shot_point_value,
FALSE AS is_three_pointer,
TRUE AS is_free_throw,
15 AS distance_ft,
'Free Throw (15 ft)' AS shot_distance_zone,
CASE WHEN ft.ft_is_made THEN 1 ELSE 0 END AS points_generated,
NULL::BOOLEAN AS team_had_lead,
NULL::BIGINT AS team_score_at_shot,
NULL::BIGINT AS opponent_score_at_shot,
NULL::INT AS score_margin_at_shot,
FALSE AS is_clutch_shot,
TRUE AS has_game_match,
'box_score_ft' AS shot_source,
CURRENT_TIMESTAMP AS created_at,
CURRENT_TIMESTAMP AS updated_at,
CURRENT_TIMESTAMP AS dbt_loaded_at
FROM (
SELECT * FROM ft_made_expanded
UNION ALL
SELECT * FROM ft_missed_expanded
) AS ft
),
final AS (
SELECT * FROM fg_shots
UNION ALL
SELECT * FROM ft_shots
)
SELECT * FROM final
@@ -0,0 +1,85 @@
{{
config(
materialized='table',
schema='intermediate',
tags=["intermediate"]
)
}}
WITH basic_stats AS (
SELECT
s.*,
map.team_abbr AS team_conformed
FROM {{ ref('stg_team_game_basic_stats') }} AS s
LEFT JOIN {{ ref('team_maps') }} AS map
ON s.team = map.team_abbr
LEFT JOIN {{ ref('stg_games') }} AS g
ON s.game_id = g.game_id
WHERE (g.season_start_year >= map.start_year AND g.season_start_year < map.end_year)
),
adv_stats AS (
SELECT
s.*,
map.team_abbr AS team_conformed
FROM {{ ref('stg_team_game_adv_stats') }} AS s
LEFT JOIN {{ ref('team_maps') }} AS map
ON s.team = map.team_abbr
LEFT JOIN {{ ref('stg_games') }} AS g
ON s.game_id = g.game_id
WHERE (g.season_start_year >= map.start_year AND g.season_start_year < map.end_year)
),
games AS (
SELECT
g.game_id,
g.game_date,
g.season_start_year,
g.is_playoff,
home_map.team_abbr AS home_team_abbr,
visitor_map.team_abbr AS visitor_team_abbr,
winning_map.team_abbr AS winning_team_abbr
FROM {{ ref('stg_games') }} g
LEFT JOIN {{ ref('team_maps') }} AS home_map ON g.home_team = home_map.full_name
LEFT JOIN {{ ref('team_maps') }} AS visitor_map ON g.visitor_team = visitor_map.full_name
LEFT JOIN {{ ref('team_maps') }} AS winning_map ON g.winning_team = winning_map.full_name
WHERE (g.season_start_year >= home_map.start_year AND g.season_start_year < home_map.end_year)
AND (g.season_start_year >= visitor_map.start_year AND g.season_start_year < visitor_map.end_year)
AND (g.season_start_year >= winning_map.start_year AND g.season_start_year < winning_map.end_year)
),
final AS (
SELECT
b.game_id,
b.team_conformed AS team,
g.game_date,
g.season_start_year,
g.is_playoff,
CASE WHEN b.team_conformed = g.winning_team_abbr THEN 'W' ELSE 'L' END AS game_result,
CASE
WHEN b.team_conformed = g.home_team_abbr THEN g.visitor_team_abbr
ELSE g.home_team_abbr
END AS opponent_team,
b.points,
a.offensive_rating,
a.defensive_rating,
a.net_rating,
b.pace,
b.effective_fg_pct,
b.turnover_rate,
b.offensive_rebound_rate,
b.free_throw_rate,
a.offensive_tier,
a.defensive_tier,
a.shot_selection_style,
a.ball_movement_style,
a.ball_security_tier,
a.defensive_activity
FROM basic_stats AS b
LEFT JOIN adv_stats AS a
ON b.game_id = a.game_id AND b.team_conformed = a.team_conformed
LEFT JOIN games AS g
ON b.game_id = g.game_id
)
SELECT * FROM final