Tipping Points

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

Domain
SQL
Difficulty
hard
Seniority
L5
Asked in
Robinhood

Problem

We run health checks across our services and need to audit unexpected state changes. Surface every reading where a service's status differs from its previous check, showing the old and new status side by side.

A service's health is a story told in how it turns. Find every turn.

Tables

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 5 of 159 rows
svc_namecheckedprevious_statuscurrent_status
auth-svc2026-01-08 21:03:00healthyDEGRADED
auth-svc2026-02-11 10:50:00DEGRADEDHealthy
auth-svc2026-02-18 19:13:00Healthytimeout
auth-svc2026-03-10 11:53:00timeoutdegraded
auth-svc2026-03-21 20:40:00degradedunhealthy

Worked solution and explanation

What this really is

This is a per-service change detector wearing a monitoring costume. The skill being probed: can you line up each reading against the one immediately before it, within the same service, and flag where the two differ? Anyone can eyeball a status column and watch it flip. The trap is ordering. Sort by timestamp across the whole table and you compare a 'payment-api' reading to an 'auth-svc' reading, manufacturing garbage transitions at every hop between services. You have to scope the look-back to one service at a time, ordered inside that scope. Get the partition wrong and almost every row looks like a change; forget to drop each service's very first reading and you emit a phantom transition against nothing.


Break down the requirements

Step 1: Attach each row's prior status in a CTE

Compute the prior status for each reading with LAG(status) OVER (PARTITION BY svc_name ORDER BY checked). Partitioning by svc_name keeps the look-back inside one service so you never compare across services; ordering by checked makes 'previous' mean the immediately earlier reading.

Step 2: Keep only the genuine transitions

The outer query keeps only real transitions. previous_status IS DISTINCT FROM current_status flags any reading whose status differs from the one before it. That comparison treats a NULL previous as different from everything, which is exactly why previous_status IS NOT NULL is load-bearing: without it, every service's first reading (whose LAG is NULL) would surface as a bogus change against nothing. IS DISTINCT FROM is also a raw, case-sensitive comparison, so a 'Healthy' to 'healthy' flip counts. The audit is a set of transitions with no promised order, so there is no outer sort to write.


The solution

Lag over `svc_name` partitions to surface status flips
WITH with_prev AS (
    SELECT svc_name, checked, status AS current_status, LAG(status) OVER (PARTITION BY svc_name ORDER BY checked) AS previous_status
    FROM svc_health
)
SELECT svc_name, checked, previous_status, current_status
FROM with_prev
WHERE previous_status IS NOT NULL AND previous_status IS DISTINCT FROM current_status

Common follow-up questions