Top Regions by Critical Alerts

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

Problem

List the top 5 regions by number of critical alerts in alert_events, highest count first. An alert records only its service, so we place it in a region through that service's checks in svc_health.

Which regions have the highest volume of critical alerts

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

svc_health

Columns: check_id INTEGER, svc_name TEXT, status TEXT, latency REAL, uptime REAL, checked TEXT, region TEXT

svc_health: 10 of 200 rows
check_idsvc_namestatuslatencyuptimecheckedregion
137payment-apidegraded3.697.032026-02-02 01:05:00us-west-2
174user-svcunhealthy6.794.062026-03-03 02:10:00eu-west-1
211search-apitimeout9.891.092026-04-04 03:15:00ap-south-1
248gatewayHealthy12.998.122026-05-05 04:20:00eu-central-1
285notif-svcDEGRADED1695.152026-06-06 05:25:00us-east-1
322ml-servinghealthy19.192.182026-07-07 06:30:00us-west-2
359cache-svcdegradedNULL99.212026-08-08 07:35:00eu-west-1
396queue-workerunhealthy25.396.242026-09-09 08:40:00ap-south-1
433cron-svctimeout28.493.272026-01-10 09:45:00eu-central-1
470auth-svcHealthy31.590.32026-02-11 10:50:00us-east-1

Expected output

First 4 of 4 rows
regioncritical_count
eu-central-1308
eu-west-1288
us-east-1160
us-west-2144

Worked solution and explanation

What this really is

This is a dirty-label filter plus a region lookup that lives in the wrong table, dressed up as a postmortem leaderboard. Anyone can write the join and the GROUP BY. What separates candidates is reading the severity sample rows before typing: 'critical' and 'Critical' are both there, and each is about half of the critical alerts. Filter on the lowercase spelling alone and every region's count halves, 'eu-west-1' lands level with 'eu-central-1' at 144, and the top of the list stops meaning anything.

The second decision is the grain. alert_events has no region, so the region has to come from svc_health, which holds many checks per service. 'auth-svc', 'user-svc' and 'gateway' each show up in two regions. The expected counts (308, 288, 160, 144) are per alert-to-check match, not per alert, so reconcile against the preview before you reach for a dedupe.

Step 1: Filter severity across both spellings

WHERE ae.severity IN ('critical', 'Critical') keeps both casings the data holds. LOWER(ae.severity) = 'critical' would also survive a third spelling arriving later, and on this data it matches the same rows. Either way, the filter sits on the alert side so the join only ever sees critical rows.

Step 2: Attach the region from svc_health

Inner-join alert_events to svc_health on svc_name. 'db-primary' fires critical alerts but has no health checks, so it has no region to report under and the inner join drops it. Every critical alert pairs with every check of its service, which is exactly the grain the preview counts.

Step 3: Count the matches per region

GROUP BY sh.region with COUNT(*) AS critical_count counts the joined pairs. 'ap-south-1' never appears: none of the services that both fire critical alerts and have checks is checked there.

Step 4: Cut at five, keeping ties

RANK() OVER (ORDER BY COUNT(*) DESC) numbers the regions by volume, and rnk <= 5 keeps every region tied at the fifth spot instead of letting LIMIT 5 drop one arbitrarily. On this data only four regions have critical alerts, so all four come back, highest count first.

Top regions by critical alerts
SELECT region, critical_count
FROM (
  SELECT
    sh.region,
    COUNT(*) AS critical_count,
    RANK() OVER (ORDER BY COUNT(*) DESC) AS rnk
  FROM alert_events ae
  INNER JOIN svc_health sh
    ON ae.svc_name = sh.svc_name
  WHERE ae.severity IN ('critical', 'Critical')
  GROUP BY sh.region
) ranked
WHERE rnk <= 5
ORDER BY critical_count DESC;
One spelling
WHERE ae.severity = 'critical' keeps half the critical rows: 'eu-central-1' 144, 'eu-west-1' 144, 'us-east-1' 80, 'us-west-2' 64. The top two tie and every count is off by half.
Both spellings
ae.severity IN ('critical', 'Critical') keeps them all: 'eu-central-1' 308, 'eu-west-1' 288, 'us-east-1' 160, 'us-west-2' 144. That is the result that grades.

Follow-up questions

Common follow-up questions