Kathuko › SQL › Part 3: Aggregation

3.4 19c+

Practice: three aggregation problems

Three questions on GROUP BY and friends. Expected rows first, answers behind a tap. Bowl to your field.

1. Economy rates

2026 bowlers who bowled at least 72 legal balls (12 overs): balls, runs conceded (off the bat plus wides and no-balls; byes and leg-byes don't count against the bowler), wickets, and economy (runs per six balls, two decimals). Best economy first.

Expected result · 30 rows
PLAYER_NAMEBALLSRUNSWICKETSECONOMY
Logan Pryce12013976.95
Imraan Patel10712887.18
Tom Blackwood14117177.28
Will Ashdown14417627.33
Sione Fifita11414057.37
Waqas Jamil10813487.44
Andile Zulu10814057.78
Kemar Joseph10814087.78
Haris Raza11014467.85
Jack Mercer136178107.85
Gokul Prakash13818167.87
Naveen Reddy12517098.16
Freddie Lowe13818978.22
Arvind Selvam13819158.3
Zubair Lodhi12016788.35
Asif Mirza11516468.56
Archie Muir11416458.63
Ethan Park10214748.65
Senthil Murugan13519658.71
Nico Tamihana11817258.75
Tyler Vance8512418.75
Yusuf Moosa12017578.75
Rory Paterson11817698.95
Wian Brits11617358.95
Kyle Fourie10616449.28
Harish Kumar13822199.61
Callum Reid13922729.8
Omar Haddad9014829.87
Danish Ansari104186410.73
Nikhil Rao86157210.95
Try itShow the answer
select p.player_name,
       sum(b.is_legal)                                                                        as balls,
       sum(b.runs_batter + case when b.extra_type in ('WD', 'NB') then b.runs_extras else 0 end) as runs,
       sum(b.is_bowler_wicket)                                                                as wickets,
       round(6 * sum(b.runs_batter + case when b.extra_type in ('WD', 'NB') then b.runs_extras else 0 end)
             / sum(b.is_legal), 2)                                                            as economy
from   cr_balls_v b
join   cr_players p on p.player_id = b.bowler_id
where  b.season = 2026
group  by p.player_name
having sum(b.is_legal) >= 72
order  by economy, p.player_name;
select player_name, balls, runs, wickets, round(6 * runs / balls, 2) as economy
from   (select p.player_name,
               sum(o.balls)   as balls,
               sum(o.runs)    as runs,
               sum(o.wickets) as wickets
        from   (select bowler_id, match_id, over_no,
                       sum(is_legal) as balls,
                       sum(runs_batter + case when extra_type in ('WD', 'NB') then runs_extras else 0 end) as runs,
                       sum(is_bowler_wicket) as wickets
                from   cr_balls_v
                where  season = 2026
                group  by bowler_id, match_id, over_no) o
        join   cr_players p on p.player_id = o.bowler_id
        group  by p.player_name)
where  balls >= 72
order  by economy, player_name;

Count legal balls rather than overs: the last over of a chase (or of an all-out innings) can stop after two or three balls, and counting it as a whole over would flatter the bowler. The second answer aggregates twice, balls into overs and overs into bowlers, which gives the same totals.

2. Boundaries by phase

For each season, the number of fours and sixes in each phase, with a season total. Use ROLLUP, and label the total "All phases".

Expected result · 8 rows
SEASONPHASEFOURSSIXES
2025Death8458
2025Middle19080
2025Powerplay17437
2025All phases448175
2026Death6043
2026Middle19585
2026Powerplay21455
2026All phases469183
Try itShow the answer
select b.season,
       case when grouping(b.phase) = 1 then 'All phases' else b.phase end as phase,
       sum(b.is_four) as fours,
       sum(b.is_six)  as sixes
from   (select season, is_four, is_six,
               case when over_no <= 6 then 'Powerplay' when over_no >= 17 then 'Death' else 'Middle' end as phase
        from   cr_balls_v) b
group  by b.season, rollup (b.phase)
order  by b.season, grouping(b.phase), b.phase;
select b.season,
       case when grouping(b.phase) = 1 then 'All phases' else b.phase end as phase,
       sum(b.is_four) as fours,
       sum(b.is_six)  as sixes
from   (select season, is_four, is_six,
               case when over_no <= 6 then 'Powerplay' when over_no >= 17 then 'Death' else 'Middle' end as phase
        from   cr_balls_v) b
group  by grouping sets ((b.season, b.phase), (b.season))
order  by b.season, grouping(b.phase), b.phase;

(The b. prefixes avoid the alias trap from page 3.1.) GROUP BY season, ROLLUP (phase) is a partial rollup: season is always grouped, phase is rolled up within it, so there's no grand total row.

3. Toss decisions

How often did toss winners choose to bat and to field, and how often did that choice win the match?

Expected result · 2 rows
TOSS_DECISIONTIMESTOSS_WINNER_WON
BAT115
FIELD2115
Try itShow the answer
select toss_decision,
       count(*)                                                      as times,
       count(case when winner_id = toss_winner_id then 1 end)        as toss_winner_won
from   cr_matches
group  by toss_decision
order  by toss_decision;
select toss_decision,
       count(*)                                                       as times,
       sum(case when winner_id = toss_winner_id then 1 else 0 end)    as toss_winner_won
from   cr_matches
group  by toss_decision
order  by toss_decision;

Part 3 quiz

5 questions on all of Part 3. Get 4 right to pass. Retake it as often as you like.