Error Hall of Fame

An easy SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.

Domain
SQL
Difficulty
easy
Seniority
L3
Asked in
City and County of San Francisco

Problem

The on-call team's weekly error review lists TypeError and TYPEERROR as two separate problems, which splits the biggest offender in half. Rebuild the review from the err_tracks table: every error type with how many times it occurred, most frequent first.

The year's worst error categories.

Tables

err_tracks

Columns: err_id INTEGER, err_type TEXT, message TEXT, svc_name TEXT, severity TEXT, count INTEGER, first_at TEXT

err_tracks: 10 of 200 rows
err_iderr_typemessagesvc_nameseveritycountfirst_at
137TypeErrorCannot read property of undefinedpayment-apierror82026-02-02 01:11:00
174ConnectionTimeoutConnection timed out after 30suser-svcwarning152026-03-03 02:22:00
211OutOfMemoryHeap space exhaustedsearch-apiinfo222026-04-04 03:33:00
248FileNotFoundFile /tmp/data.csv not foundgatewayFatal292026-05-05 04:44:00
285PermissionDeniedAccess denied for user rootworkerERROR362026-06-06 05:55:00
322RateLimitExceededToo many requests from 10.0.0.1auth-svcfatal432026-07-07 06:06:00
359ParseErrorMalformed JSON in request bodypayment-apierror502026-08-08 07:17:00
396nullpointerexceptionStack overflow in recursive calluser-svcwarning572026-09-09 08:28:00
433TYPEERRORDivision by zerosearch-apiinfo642026-01-10 09:39:00
470NullPointerExceptionUnexpected null value at line 42gatewayFatalNULL2026-02-11 10:50:00

Expected output

First 5 of 8 rows
error_typeoccurrences
typeerror39489
nullpointerexception34252
connectiontimeout19370
permissiondenied18765
parseerror18553

Worked solution and explanation

This is a rollup read dressed up as an error leaderboard. err_tracks does not hold one row per error event: each row is a tracked error with its own tally in count, and the same error is spelled more than one way in err_type. Anyone can write a grouped count. What separates candidates is reading the row before writing the query. If you count rows, every raw spelling ties at 20. If you group the raw string, TypeError shows up twice, so the real leader, 'typeerror' at 39,489, never appears as one line.

Two ways the obvious query lies

Step 1: Decide what one row means

Look at the sample before you write the aggregate. count holds 8, 15, 22: those are occurrences the tracker already tallied, so a type's total is SUM(count). COUNT(*) answers a different question (how many tracked errors exist), and on this seed it returns 20 for every spelling.

Step 2: Fold the spelling before you group

'TypeError' and 'TYPEERROR' are one error. Group on LOWER(err_type) and alias it error_type, so the bucket and the label are the same expression. Grouping the raw column keeps 10 rows where the review needs 8.

Step 3: Sort by the total, biggest first

ORDER BY occurrences DESC puts triage's first stop on top. The eight totals all differ on this data, so no tiebreaker is needed.

Tally pre-counted errors by folded type
SELECT
  LOWER(err_type) AS error_type,
  SUM(count)      AS occurrences
FROM err_tracks
GROUP BY LOWER(err_type)
ORDER BY occurrences DESC;
Row count on the raw spelling
GROUP BY err_type with COUNT(*): 10 rows, every one showing 20. 'TYPEERROR' and 'TypeError' sit on separate lines, and nothing in the list says which error fires most.
Tally on the folded spelling
GROUP BY LOWER(err_type) with SUM(count): 8 rows, 'typeerror' at 39,489 on top and 'nullpointerexception' at 34,252 second. The order finally means something.

Common follow-up questions