Alert Response Breakdown

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

Domain
SQL
Difficulty
medium
Seniority
L4
Asked in
City and County of San Francisco

Problem

Every row of alert_events is one fired alert, with severity recorded in inconsistent letter case and ack_by left empty when nobody acknowledged it. Across the whole table, each service needs its total alerts, how many were critical, how many were high, and how many were never acknowledged. Alongside those comes the average number of alerts per status category the service saw, to two decimal places, with the busiest services first and alphabetical among equal totals.

An on-call postmortem asks which services are bleeding alerts nobody acknowledges.

Tables

alert_events

Columns: alert_id INTEGER, svc_name TEXT, severity TEXT, status TEXT, fired_at TEXT, ack_by TEXT, resolved TEXT

alert_events: 10 of 200 rows
alert_idsvc_nameseveritystatusfired_atack_byresolved
129payment-apihighacknowledged2026-02-02 01:07:00bob2026-02-02 03:11:00
158user-svcmediumresolved2026-03-03 02:14:00charlie2026-03-03 04:22:00
187search-apilowsilenced2026-04-04 03:21:00danaNULL
216gatewayCriticalfiring2026-05-05 04:28:00NULL2026-05-05 06:44:00
245notif-svcHIGHacknowledged2026-06-06 05:35:00alice2026-06-06 07:55:00
274db-primarycriticalresolved2026-07-07 06:42:00bobNULL
303cache-01highsilenced2026-08-08 07:49:00charlie2026-08-08 09:17:00
332auth-svcmediumfiring2026-09-09 08:56:00NULL2026-09-09 10:28:00
361payment-apilowacknowledged2026-01-10 09:03:00eveNULL
390user-svcCriticalresolved2026-02-11 10:10:00alice2026-02-11 12:50:00

Expected output

First 5 of 8 rows
svc_nametotal_alertscritical_counthigh_countunacked_countavg_per_status
gateway261802626
payment-api26018026
search-api26016026
auth-svc241602424
cache-0124016024

Worked solution and explanation

Why this problem exists in real interviews

This tests whether you reach for conditional aggregation on instinct. The wide output (critical_count, high_count, unacked_count side by side) is the tell. A junior writes three subqueries or a self-join; you collapse it into one pass over alert_events with SUM(CASE WHEN ...) per bucket. The LOWER(severity) requirement and the per-status average are the two places people slip.


Break down the requirements

Step 1: One pass, group by service

GROUP BY svc_name. Everything else, totals, severity buckets, unacked, per-status average, comes from a single scan over alert_events. No subqueries needed.

Step 2: Normalize severity in the CASE

LOWER(severity) = 'critical' inside each SUM(CASE WHEN ...). Cheap because the comparison happens row by row during the aggregate, not in a WHERE that would prune data.

Step 3: Unacked count via NULL

SUM(CASE WHEN ack_by IS NULL THEN 1 ELSE 0 END). Do not use COUNT(ack_by) and subtract from total; that works but obscures intent in a wide pivot.

Step 4: Avg alerts per status

COUNT(*) * 1.0 / COUNT(DISTINCT status) inside ROUND(..., 2). The 1.0 * forces float division so MySQL / Postgres do not truncate. COUNT(DISTINCT) is the second pass the planner needs.

Step 5: Order by volume

ORDER BY total_alerts DESC. The aggregate alias is fine to reference here in every major engine.


The solution

CONDITIONAL-AGG PIVOT IN ONE PASS
SELECT
  svc_name,
  COUNT(*) AS total_alerts,
  SUM(CASE WHEN LOWER(severity) = 'critical' THEN 1 ELSE 0 END) AS critical_count,
  SUM(CASE WHEN LOWER(severity) = 'high'     THEN 1 ELSE 0 END) AS high_count,
  SUM(CASE WHEN ack_by IS NULL              THEN 1 ELSE 0 END) AS unacked_count,
  ROUND(1.0 * COUNT(*) / COUNT(DISTINCT status), 2) AS avg_per_status
FROM alert_events
GROUP BY svc_name
ORDER BY total_alerts DESC, svc_name;
Pivot via conditional agg (idiomatic)
One pass, output already wide. SUM(CASE WHEN LOWER(severity)='critical' ...) per bucket, grouped only by svc_name. Hands the BI tool a ready table.
GROUP BY (`svc_name`, severity) then reshape
Long format: one row per (service, severity). Correct, but you need a PIVOT (Snowflake/SQL Server) or a wrapping conditional agg anyway to widen it. Two-step for no win.

COMMON FOLLOW-UP QUESTIONS

Common follow-up questions