Log Entries by Level

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
Yelp

Problem

The SRE dashboard needs a count of server log entries at each log level, alphabetically by level.

Info, warn, error, fatal. The breakdown matters.

Tables

server_logs

Columns: log_id INTEGER, server_name TEXT, log_level TEXT, message TEXT, response_time_ms INTEGER, log_timestamp TEXT

server_logs: 10 of 200 rows
log_idserver_namelog_levelmessageresponse_time_mslog_timestamp
137web-prod-02WARNConnection timeout after 30s232026-02-02 01:07:13
174api-prod-01ERRORDatabase query slow: 2.5sNULL2026-03-03 02:14:26
211api-prod-02DEBUGCache miss for key user_123492026-04-04 03:21:39
248db-primaryCRITICALMemory usage at 85%02026-05-05 04:28:52
285db-replica-01INFOSSL certificate expires in 7 daysNULL2026-06-06 05:35:05
322cache-01WARNRate limit exceeded for IP 192.168.1.x882026-07-07 06:42:18
359worker-01ERRORDisk space low: 10% remaining1012026-08-08 07:49:31
396cdn-edge-usDEBUGNew deployment v2.3.1 startedNULL2026-09-09 08:56:44
433cdn-edge-euCRITICALHealth check passed1272026-01-10 09:03:57
470monitor-01INFOFailed to connect to upstream1402026-02-11 10:10:10

Expected output

First 5 of 5 rows
log_levelentry_count
CRITICAL40
DEBUG40
ERROR40
INFO40
WARN40

Worked solution and explanation

This is a grain question wearing a dashboard costume. The whole job is deciding that the answer has one row per log_level, and that each row counts every line in server_logs, not something about the lines. Nobody fumbles the syntax. The slip is in the count: reach for COUNT(DISTINCT message) because 'entries' sounds like unique alerts, and every level reads 19 instead of 40, because the same message repeats inside a level. Lose the per-level grain entirely and you hand the dashboard a single 200 it cannot plot.

Walk the grain first

Step 1: Name the grain before the query

Say it out loud: one row per log level. log_level holds five values on this data ('CRITICAL', 'DEBUG', 'ERROR', 'INFO', 'WARN'), so the answer is five rows, and GROUP BY log_level is what produces exactly that shape.

Step 2: Count lines, not messages

COUNT(*) counts every row in the group. A repeated alert is still a separate log line, and message repeats inside every level, so COUNT(DISTINCT message) quietly reports 19 where the truth is 40.

Step 3: Sort by the name, not the number

The listing is alphabetical, so ORDER BY log_level ASC. Every level happens to hold 40 lines here, so sorting by entry_count would hand back the five rows in whatever order the engine pleases.

One row per level, A to Z
SELECT log_level, COUNT(*) AS entry_count
FROM server_logs
GROUP BY log_level
ORDER BY log_level ASC
Counts unique messages
COUNT(DISTINCT message) collapses repeated alerts, so each level shows 19: the number of different texts, not the volume the dashboard is tracking.
Counts every line
COUNT(*) counts each row of server_logs once, so each level shows its true 40 lines, repeats included.

Common follow-up questions