Duplicated User Event Messages
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
What feed does an engineer load-testing the consumers replay when she pushes twice the normal volume of the 'user-events' topic in stream_msgs, with every message sent as two identical copies? She replays that feed in message ID order.
Duplicated messages from the alerts topic.
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
| msg_id | topic | part_key | payload | produced | consumer |
|---|---|---|---|---|---|
| 13160 | user-events | key-20 | {"event": "type_0", "ts": 1700144000, "data": {"id": 40}} | 2026-05-13 16:40:40 | analytics-svc |
| 13160 | user-events | key-20 | {"event": "type_0", "ts": 1700144000, "data": {"id": 40}} | 2026-05-13 16:40:40 | analytics-svc |
| 16320 | user-events | key-40 | {"event": "type_0", "ts": 1700288000, "data": {"id": 80}} | 2026-09-01 08:20:20 | analytics-svc |
| 10017940 | user-events | key-20 | {"event": "type_0", "ts": 1700144000, "data": {"id": 40}} | 2026-04-13 16:40:40 | analytics-svc |
| 10017980 | user-events | key-40 | {"event": "type_0", "ts": 1700288000, "data": {"id": 80}} | 2026-08-01 08:20:20 | analytics-svc |
Worked solution and explanation
It is a fan-out, not a dedup
Strip the Kafka costume and this is a controlled row fan-out: take the 'user-events' slice of stream_msgs and emit each row exactly twice. The entire problem hinges on one keyword choice. UNION ALL keeps every duplicate; plain UNION silently throws them away. On the seed that is the difference between 8 rows and 4. Candidates who reach for UNION because it 'reads cleaner' ship a load test at half the intended throughput while every dashboard reports green.
Build it in three moves
Step 1: Carve out the user-events slice
Filter stream_msgs to topic = 'user-events' and project only the six columns the replay tool needs: msg_id, topic, part_key, payload, produced, consumer. offset is intentionally left out: a replayed message lands at a new offset, so it is not part of the identity you are copying.
Step 2: Stack the slice onto itself
Write that filtered slice once, then stack a byte-identical copy beneath it with UNION ALL between the two SELECT statements. ALL is the load-bearing word: it preserves duplicates, so every qualifying row now appears exactly twice. Swap in plain UNION and the two copies fold back into one.
Step 3: Sort the combined feed by msg_id
Name the doubled slice as the CTE doubled, then put a single ORDER BY msg_id on the outer select. The CTE makes it obvious to a reader that the sort applies to the combined result rather than to one branch, and it puts the two copies of each message next to each other in the order the replayer sends them.
The solution
WITH doubled AS (
SELECT msg_id, topic, part_key, payload, produced, consumer
FROM stream_msgs
WHERE topic = 'user-events'
UNION ALL
SELECT msg_id, topic, part_key, payload, produced, consumer
FROM stream_msgs
WHERE topic = 'user-events'
)
SELECT msg_id, topic, part_key, payload, produced, consumer
FROM doubled
ORDER BY msg_idTwo identical filtered SELECTs combined by UNION ALL inside a CTE, with ORDER BY msg_id on the outer select so every qualifying row lands twice.
- UNION ALL (correct)
- Keeps every row from both branches. The four matching messages become eight output rows: exactly the doubled load you asked for.
- UNION (wrong)
- Applies an implicit distinct across the combined set. The two identical copies collapse into one, so four messages stay four rows and the replay adds no load.
Common follow-up questions
- If the replay factor became configurable to N copies instead of 2, how would you produce N without writing N stacked SELECTs? (Tests generalizing a fixed fan-out into a parameterized join.)
- Going the other direction: how would you collapse genuine replay duplicates and keep only the earliest offset per message? (Tests `ROW_NUMBER` partitioning to pick a single occurrence.)
- How would you stop replayed duplicates from being double-counted at the consumer level in the first place? (Tests idempotent consumer design beyond SQL.)