Low-Volume Stream Topics
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
- L3
- Asked in
- Amazon
Problem
We run a streaming platform and are building a compaction worklist of the quietest topics. List each topic that carries fewer than 6 messages, along with its message count.
Quiet topics in the stream.
Tables
stream_msgs
Columns: msg_id INTEGER, topic TEXT, part_key TEXT, payload TEXT, offset INTEGER, produced TEXT, consumer TEXT
| msg_id | topic | part_key | payload | offset | produced | consumer |
|---|---|---|---|---|---|---|
| 10079 | order-updates | key-3 | {"event": "type_1", "ts": 1700003600, "data": {"id": 1}} | 100 | 2026-02-02 01:07:13 | search-indexer |
| 10158 | page-views | key-6 | {"event": "type_2", "ts": 1700007200, "data": {"id": 2}} | 200 | 2026-03-03 02:14:26 | ml-pipeline |
| 10237 | click-stream | key-9 | {"event": "type_3", "ts": 1700010800, "data": {"id": 3}} | 300 | 2026-04-04 03:21:39 | reporting-svc |
| 10316 | payment-events | key-12 | {"event": "type_4", "ts": 1700014400, "data": {"id": 4}} | 400 | 2026-05-05 04:28:52 | NULL |
| 10395 | inventory-sync | key-15 | {"event": "type_5", "ts": 1700018000, "data": {"id": 5}} | 500 | 2026-06-06 05:35:05 | notification-svc |
| 10474 | audit-log | key-18 | {"event": "type_6", "ts": 1700021600, "data": {"id": 6}} | 600 | 2026-07-07 06:42:18 | NULL |
| 10553 | metric-ingest | NULL | {"event": "type_7", "ts": 1700025200, "data": {"id": 7}} | 700 | 2026-08-08 07:49:31 | data-warehouse |
| 10632 | Una Bennett | key-24 | {"event": "type_8", "ts": 1700028800, "data": {"id": 8}} | 800 | 2026-09-09 08:56:44 | NULL |
| 10711 | Van Wood | key-27 | {"event": "type_9", "ts": 1700032400, "data": {"id": 9}} | 900 | 2026-01-10 09:03:57 | fraud-detector |
| 10790 | Wes Barnes | key-30 | {"event": "type_0", "ts": 1700036000, "data": {"id": 10}} | 1000 | 2026-02-11 10:10:10 | analytics-svc |
Expected output
| topic | msg_count |
|---|---|
| Han Washington | 4 |
| Isa Butler | 4 |
| Joy Simmons | 4 |
| Kai Foster | 4 |
| Lea Gonzales | 4 |
Worked solution and explanation
What this really asks
Beneath the compaction story this is a filter on a GROUP, not on a row. You are asked for topics whose *total* message count sits under a threshold, and that total does not exist until every row for a topic has been folded together. Anyone can write GROUP BY topic; what separates people is knowing the threshold has to ride on HAVING COUNT(*) < 6, because WHERE runs before the grouping and never sees the count. Reach for WHERE COUNT(*) < 6 and the query will not even compile.
Build it
Step 1: Collapse each topic into one group
GROUP BY topic folds every message that shares a topic into a single group, including rows with a null consumer or part_key. Those are real messages and belong in the count.
Step 2: Count the messages per topic
COUNT(*) counts every row in each group. Use COUNT(*), not COUNT(consumer), so null-consumer rows are not silently dropped from the tally.
Step 3: Keep only the quiet groups
HAVING COUNT(*) < 6 runs after the grouping and keeps only the topics whose total is under the threshold. A topic sitting at exactly 6 is busy enough to keep, so it is excluded.
SELECT topic, COUNT(*) AS msg_count
FROM stream_msgs
GROUP BY topic
HAVING COUNT(*) < 6- WHERE (wrong)
WHERE COUNT(*) < 6fails: at row-filter time there is no group yet and no count to compare against. No row-level predicate can express a per-topic total.- HAVING (right)
HAVING COUNT(*) < 6runs afterGROUP BY topiccollapses each topic to one row, so the count exists and the threshold applies to the whole group.
Common follow-up questions
- How would the query change if you needed topics with between 6 and 20 messages instead? (Tests whether the candidate can express a compound threshold on the aggregate.)
- Why can this threshold not be expressed with a `WHERE` clause? (Tests understanding of pre-aggregation versus post-aggregation filtering.)
- If you also had to ignore messages from one specific `consumer`, where would that filter go, and why? (Tests that row-level filters belong in `WHERE` while group-level filters belong in `HAVING`.)