Built and run by one person.

Why is my cricket SQL query returning the wrong numbers?

Usually the SQL is correct and a column does not mean what its name suggests. That is what makes this class expensive: nothing errors, a plausible number comes back, and it is wrong by a margin small enough to survive a sanity check.

The extras columns are blank, not zero. Cricsheet leaves wides, no balls, byes, leg byes and penalty empty when they do not apply, while runs_off_bat and extras carry a real zero. So wides = 0 matches no rows in the whole table. Wrap them in coalesce.

The wides column holds runs, not a count. A plain wide is 1 and a wide that runs away to the boundary is 5, so wides = 1 misses about one wide in ten and summing the column gives you runs. To count them, use wides is not null. And extras is the total, with the five named columns as its breakdown; every row adds up exactly.

team1 and team2 are the order the two sides are listed in, not who batted first. In T20s the side listed second did bat second about nine times in ten, so using team2 as the chasing side is wrong for roughly one match in ten. Take batting order from the margin columns instead: winner_runs means the side batting first won, winner_wickets means the side batting second won.

winner_innings is a yes or no flag. It means the match was won by an innings, which can only happen in a Test, so filtering it to 2 returns nothing every time. Of 918 Tests in this data, 739 produced a result and 170 of those were won by an innings.

Not every wicket is the bowler's. Run outs, retired hurt and retired out all leave the bowler's name on the row, because they bowled the ball. Counting every row where wicket_type is not null hands bowlers wickets they never took, and nearly one bowler performance in seven comes out too high. Read what wicket_type holds and keep only what you want; run outs are most of it.

Four smaller ones that bite the same way. An over is not six rows and over_no starts at zero, so no amount of multiplying by six gives a ball count (the longest over here runs to twenty one deliveries). toss_decision has only two values, bat and field, with no bowl. Team names carry no gender, so the women's side is stored as Australia exactly like the men's and you filter on the gender column. And target_runs already includes the extra run needed to win, so do not add one yourself.

Two more that are about method rather than a column. Do not hardcode where the death overs start: the over number differs by format, and on a rain shortened innings a fixed threshold can return nothing at all, which reads as "there were no death overs" rather than as a filter that missed. And players are stored as name strings, so joining to another source on a name is fragile - the people and match_players tables carry stable identifiers and cross references to other cricket sites, and they are the safer join.

What each column means is Cricsheet's definition and their format page is the authority: cricsheet.org/format/csv_ashwin. If a query fails outright rather than returning a wrong number, it is usually mangled in transit: why a correct SQL query fails when sent in a URL. Database, limits and the full download: https://www.tigzig.com/apis/database. Full write-up: https://www.tigzig.com/post/cricket-database-14-things-that-trip-people-up-sep2026.

Data source is Cricsheet, licensed ODC-BY 1.0. TigZig is not affiliated with or endorsed by Cricsheet.

Building something like this? How I work covers the rates, the availability and what I take on.

← All Agents FAQ