lesson 46 Window functions · advanced
NTILE & balanced ranking buckets
Split ordered rows into ranking buckets.
the idea
NTILE(n) splits the ordered rows of a window into n buckets of as equal size as possible and returns each row’s bucket number. Use it for quartiles or deciles of a population, ordering by the measure and a tie-breaker.
Dataset: Sports
The tables the challenges use, with their first 6 rows. Under each column name: the kind of value it holds, and which table it links to.
games13 columns · 23,168 rows
| game_idtext · unique id | seasonnumber · links to seasons | game_datedate | game_numbernumber | game_typetext | venue_idtext · links to venues | home_team_idtext · links to teams | away_team_idtext · links to teams | home_scorenumber | away_scorenumber | day_nighttext | attendancenumber | duration_minutesnumber |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ANA201604040 | 2016 | 2016-04-04 | 0 | regular | ANA01 | ANA | CHN | 0 | 9 | night | 44020 | 188 |
| ANA201604050 | 2016 | 2016-04-05 | 0 | regular | ANA01 | ANA | CHN | 1 | 6 | night | 37042 | 154 |
| ANA201604070 | 2016 | 2016-04-07 | 0 | regular | ANA01 | ANA | TEX | 4 | 3 | night | 39089 | 191 |
| ANA201604080 | 2016 | 2016-04-08 | 0 | regular | ANA01 | ANA | TEX | 3 | 7 | night | 35207 | 210 |
| ANA201604090 | 2016 | 2016-04-09 | 0 | regular | ANA01 | ANA | TEX | 1 | 4 | night | 38106 | 173 |
| ANA201604100 | 2016 | 2016-04-10 | 0 | regular | ANA01 | ANA | TEX | 3 | 1 | day | 35097 | 163 |
- game_idtext · unique id
- ANA201604040
- seasonnumber · links to seasons
- 2016
- game_datedate
- 2016-04-04
- game_numbernumber
- 0
- game_typetext
- regular
- venue_idtext · links to venues
- ANA01
- home_team_idtext · links to teams
- ANA
- away_team_idtext · links to teams
- CHN
- home_scorenumber
- 0
- away_scorenumber
- 9
- day_nighttext
- night
- attendancenumber
- 44020
- duration_minutesnumber
- 188
- game_idtext · unique id
- ANA201604050
- seasonnumber · links to seasons
- 2016
- game_datedate
- 2016-04-05
- game_numbernumber
- 0
- game_typetext
- regular
- venue_idtext · links to venues
- ANA01
- home_team_idtext · links to teams
- ANA
- away_team_idtext · links to teams
- CHN
- home_scorenumber
- 1
- away_scorenumber
- 6
- day_nighttext
- night
- attendancenumber
- 37042
- duration_minutesnumber
- 154
- game_idtext · unique id
- ANA201604070
- seasonnumber · links to seasons
- 2016
- game_datedate
- 2016-04-07
- game_numbernumber
- 0
- game_typetext
- regular
- venue_idtext · links to venues
- ANA01
- home_team_idtext · links to teams
- ANA
- away_team_idtext · links to teams
- TEX
- home_scorenumber
- 4
- away_scorenumber
- 3
- day_nighttext
- night
- attendancenumber
- 39089
- duration_minutesnumber
- 191
- game_idtext · unique id
- ANA201604080
- seasonnumber · links to seasons
- 2016
- game_datedate
- 2016-04-08
- game_numbernumber
- 0
- game_typetext
- regular
- venue_idtext · links to venues
- ANA01
- home_team_idtext · links to teams
- ANA
- away_team_idtext · links to teams
- TEX
- home_scorenumber
- 3
- away_scorenumber
- 7
- day_nighttext
- night
- attendancenumber
- 35207
- duration_minutesnumber
- 210
- game_idtext · unique id
- ANA201604090
- seasonnumber · links to seasons
- 2016
- game_datedate
- 2016-04-09
- game_numbernumber
- 0
- game_typetext
- regular
- venue_idtext · links to venues
- ANA01
- home_team_idtext · links to teams
- ANA
- away_team_idtext · links to teams
- TEX
- home_scorenumber
- 1
- away_scorenumber
- 4
- day_nighttext
- night
- attendancenumber
- 38106
- duration_minutesnumber
- 173
- game_idtext · unique id
- ANA201604100
- seasonnumber · links to seasons
- 2016
- game_datedate
- 2016-04-10
- game_numbernumber
- 0
- game_typetext
- regular
- venue_idtext · links to venues
- ANA01
- home_team_idtext · links to teams
- ANA
- away_team_idtext · links to teams
- TEX
- home_scorenumber
- 3
- away_scorenumber
- 1
- day_nighttext
- day
- attendancenumber
- 35097
- duration_minutesnumber
- 163
first 6 of 23,168 rows · your queries use all of them
player_game_stats17 columns · 73,029 rows
| game_idtext · links to games | player_idtext · links to players | team_idtext · links to teams | batting_ordernumber | startednumber | plate_appearancesnumber | at_batsnumber | runsnumber | hitsnumber | doublesnumber | triplesnumber | home_runsnumber | rbinumber | walksnumber | strikeoutsnumber | stolen_basesnumber | hit_by_pitchnumber |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ANA202504040 | adelj001 | ANA | 8 | 1 | 5 | 5 | 0 | 2 | 1 | 0 | 0 | 3 | 0 | 2 | 0 | 0 |
| ANA202504040 | andet001 | ANA | 4 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| ANA202504040 | ariag002 | CLE | 8 | 1 | 4 | 2 | 1 | 1 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 |
| ANA202504040 | clase001 | CLE | NULL | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| ANA202504040 | danac001 | ANA | NULL | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| ANA202504040 | darnt001 | ANA | 9 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
- game_idtext · links to games
- ANA202504040
- player_idtext · links to players
- adelj001
- team_idtext · links to teams
- ANA
- batting_ordernumber
- 8
- startednumber
- 1
- plate_appearancesnumber
- 5
- at_batsnumber
- 5
- runsnumber
- 0
- hitsnumber
- 2
- doublesnumber
- 1
- triplesnumber
- 0
- home_runsnumber
- 0
- rbinumber
- 3
- walksnumber
- 0
- strikeoutsnumber
- 2
- stolen_basesnumber
- 0
- hit_by_pitchnumber
- 0
- game_idtext · links to games
- ANA202504040
- player_idtext · links to players
- andet001
- team_idtext · links to teams
- ANA
- batting_ordernumber
- 4
- startednumber
- 0
- plate_appearancesnumber
- 1
- at_batsnumber
- 1
- runsnumber
- 0
- hitsnumber
- 0
- doublesnumber
- 0
- triplesnumber
- 0
- home_runsnumber
- 0
- rbinumber
- 0
- walksnumber
- 0
- strikeoutsnumber
- 0
- stolen_basesnumber
- 0
- hit_by_pitchnumber
- 0
- game_idtext · links to games
- ANA202504040
- player_idtext · links to players
- ariag002
- team_idtext · links to teams
- CLE
- batting_ordernumber
- 8
- startednumber
- 1
- plate_appearancesnumber
- 4
- at_batsnumber
- 2
- runsnumber
- 1
- hitsnumber
- 1
- doublesnumber
- 0
- triplesnumber
- 0
- home_runsnumber
- 0
- rbinumber
- 0
- walksnumber
- 2
- strikeoutsnumber
- 0
- stolen_basesnumber
- 0
- hit_by_pitchnumber
- 0
- game_idtext · links to games
- ANA202504040
- player_idtext · links to players
- clase001
- team_idtext · links to teams
- CLE
- batting_ordernumber
- NULL
- startednumber
- 0
- plate_appearancesnumber
- 0
- at_batsnumber
- 0
- runsnumber
- 0
- hitsnumber
- 0
- doublesnumber
- 0
- triplesnumber
- 0
- home_runsnumber
- 0
- rbinumber
- 0
- walksnumber
- 0
- strikeoutsnumber
- 0
- stolen_basesnumber
- 0
- hit_by_pitchnumber
- 0
- game_idtext · links to games
- ANA202504040
- player_idtext · links to players
- danac001
- team_idtext · links to teams
- ANA
- batting_ordernumber
- NULL
- startednumber
- 0
- plate_appearancesnumber
- 0
- at_batsnumber
- 0
- runsnumber
- 0
- hitsnumber
- 0
- doublesnumber
- 0
- triplesnumber
- 0
- home_runsnumber
- 0
- rbinumber
- 0
- walksnumber
- 0
- strikeoutsnumber
- 0
- stolen_basesnumber
- 0
- hit_by_pitchnumber
- 0
- game_idtext · links to games
- ANA202504040
- player_idtext · links to players
- darnt001
- team_idtext · links to teams
- ANA
- batting_ordernumber
- 9
- startednumber
- 0
- plate_appearancesnumber
- 1
- at_batsnumber
- 1
- runsnumber
- 0
- hitsnumber
- 0
- doublesnumber
- 0
- triplesnumber
- 0
- home_runsnumber
- 0
- rbinumber
- 0
- walksnumber
- 0
- strikeoutsnumber
- 0
- stolen_basesnumber
- 0
- hit_by_pitchnumber
- 0
first 6 of 73,029 rows · your queries use all of them
teams6 columns · 31 rows
| team_idtext · unique id | franchise_idtext | citytext | nicknametext | leaguetext | divisiontext |
|---|---|---|---|---|---|
| ANA | ANA | Anaheim | Angels | AL | West |
| ARI | ARI | Arizona | Diamondbacks | NL | West |
| ATH | OAK | Sacramento | Athletics | AL | West |
| ATL | ATL | Atlanta | Braves | NL | East |
| BAL | BAL | Baltimore | Orioles | AL | East |
| BOS | BOS | Boston | Red Sox | AL | East |
- team_idtext · unique id
- ANA
- franchise_idtext
- ANA
- citytext
- Anaheim
- nicknametext
- Angels
- leaguetext
- AL
- divisiontext
- West
- team_idtext · unique id
- ARI
- franchise_idtext
- ARI
- citytext
- Arizona
- nicknametext
- Diamondbacks
- leaguetext
- NL
- divisiontext
- West
- team_idtext · unique id
- ATH
- franchise_idtext
- OAK
- citytext
- Sacramento
- nicknametext
- Athletics
- leaguetext
- AL
- divisiontext
- West
- team_idtext · unique id
- ATL
- franchise_idtext
- ATL
- citytext
- Atlanta
- nicknametext
- Braves
- leaguetext
- NL
- divisiontext
- East
- team_idtext · unique id
- BAL
- franchise_idtext
- BAL
- citytext
- Baltimore
- nicknametext
- Orioles
- leaguetext
- AL
- divisiontext
- East
- team_idtext · unique id
- BOS
- franchise_idtext
- BOS
- citytext
- Boston
- nicknametext
- Red Sox
- leaguetext
- AL
- divisiontext
- East
first 6 of 31 rows · your queries use all of them
worked example
Run these steps in order to see the idea before you write your own query. The step marked “the pattern” is what the challenges ask for. Running the example does not count toward progress.
Split teams into three buckets. Run this. NTILE(3) sorts teams by wins and labels each with tier 1, 2, or 3—roughly equal-sized groups for comparing standings.the pattern
example.sqlSELECT team_id, wins, NTILE(3) OVER (ORDER BY wins DESC, team_id) AS tier FROM standings WHERE season = 2025 AND as_of_date = ( SELECT last_regular_date FROM seasons WHERE season = 2025 );
Preview qualified batting averages. Run this. Only players with at least 400 plate appearances appear—the pool you will quartile in the tasks.
step-2.sqlSELECT s.player_id, SUM(s.plate_appearances) AS pa, ROUND(1.0 * SUM(s.hits) / SUM(s.at_bats), 3) AS batting_avg FROM player_game_stats s JOIN games g ON g.game_id = s.game_id WHERE g.game_type = 'regular' GROUP BY s.player_id HAVING SUM(s.plate_appearances) >= 400 ORDER BY batting_avg DESC LIMIT 10;
common mistake
NTILE balances counts, not values: tied batting averages can land in different quartiles, so a deterministic tie-breaker matters.