Return on Patience

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
General Assembly

Problem

Return the call count, success rate, average latency, and efficiency of every endpoint in the api_calls log with at least 5 calls, most efficient first. Only a status 200 counts as a success, and efficiency is an endpoint's successful calls divided by its average latency, so more good responses for less waiting scores higher.

The best answers cost the least time. Find the ones that pay off.

Tables

api_calls

Columns: call_id INTEGER, endpoint TEXT, method TEXT, status INTEGER, latency REAL, user_id INTEGER, call_time TEXT, err_msg TEXT

api_calls: 10 of 670 rows
call_idendpointmethodstatuslatencyuser_idcall_timeerr_msg
8079/api/v1/ordersPOST2004.21002026-02-02 01:07:00NULL
8158/api/v2/productsPUT2007.91972026-03-03 02:14:00NULL
8237/api/v1/searchDELETE20111.62942026-04-04 03:21:00NULL
8316/api/v1/auth/loginPATCH20415.33912026-05-05 04:28:00NULL
8395/api/v1/auth/logoutget30119NULL2026-06-06 05:35:00NULL
8474/api/v2/analyticspost40022.75852026-07-07 06:42:00Not found
8553/api/v1/paymentsGET40126.46822026-08-08 07:49:00Unauthorized
8632/api/v1/users/POST40330.17792026-09-09 08:56:00Rate limit exceeded
8711/api/v2/products/PUT40433.88762026-01-10 09:03:00Internal server error
8790/api/v1/usersDELETE50037.5NULL2026-02-11 10:10:00Bad gateway

Expected output

First 5 of 10 rows
endpointcall_countsuccess_rateavg_latencyefficiency_ratio
/api/v1/users1350.8592592592592593293.587407407407450.3951123143337967
/api/v1/orders1320.8560606060606061303.882575757575750.3718541601745092
/api/v2/products1250.856302.38145161290330.35385768349633145
/api/v1/search860.7674418604651163347.892941176470630.18971353594242987
/api/v1/auth/login740.6891891891891891309.63378378378380.16471070881468516

Worked solution and explanation

What this really tests

This is conditional aggregation wearing an SRE costume. Every column is computed over all of an endpoint's calls, while one ingredient counts only the status 200 subset, so the success test has to live inside the aggregate, not in WHERE. Then there is the quiet one: success_rate is an integer count over an integer count. Divide them as written and the engine does integer division. Every endpoint on this log has at least one failed call, so every success rate reads 0. Anyone gets the GROUP BY; what separates candidates is knowing which division needs help and which does not.

Building it

Step 1: Aggregate every call per endpoint

Group by endpoint and take COUNT(*) for volume and AVG(latency) for typical wait. AVG skips the null latencies on its own, while COUNT(*) still counts those calls.

Step 2: Count successes inside the aggregate

SUM(CASE WHEN status = 200 THEN 1 ELSE 0 END) is the success count. A 201 or 204 is not a success here, so test for 200 exactly rather than a 2xx range.

Step 3: Force a real fraction for the success rate

The success count over COUNT(*) is integer over integer, so wrap the numerator in CAST(... AS REAL). The efficiency division needs no cast: AVG(latency) is already a real, so dividing by it keeps the fraction.

Step 4: Drop thin endpoints and sort

HAVING COUNT(*) >= 5 filters groups, because the threshold is on an aggregate that does not exist until after grouping. Then sort by efficiency_ratio DESC.

The solution

One grouped pass: conditional count, a real success rate, efficiency over average latency
SELECT endpoint,
       COUNT(*) AS call_count,
       CAST(SUM(CASE WHEN status = 200 THEN 1 ELSE 0 END) AS REAL) / COUNT(*) AS success_rate,
       AVG(latency) AS avg_latency,
       SUM(CASE WHEN status = 200 THEN 1 ELSE 0 END) / AVG(latency) AS efficiency_ratio
FROM api_calls
GROUP BY endpoint
HAVING COUNT(*) >= 5
ORDER BY efficiency_ratio DESC
Wrong: filter successes first
WHERE status = 200 before GROUP BY makes call_count the success count, success_rate 1.0 everywhere, and avg_latency an average of successful calls only.
Right: count successes in the aggregate
SUM(CASE WHEN status = 200 THEN 1 ELSE 0 END) counts successes while COUNT(*) and AVG(latency) still see every call.

Common follow-up questions