runtime
50 / 88

lesson 50 Advanced product analysis · advanced

Deduplicate event retries

Identify repeated events and keep a consistent record.

the idea

Clients retry when a delivery times out, so one logical event can arrive several times with the same event_id. Keep one delivery per event_id with ROW_NUMBER() OVER (PARTITION BY event_id ORDER BY received_at, delivery_id) = 1, then count logical events.

Dataset: Product / SaaS Analytics

The tables the challenges use, with their first 6 rows. Under each column name: the kind of value it holds, and which table it links to.

events8 columns · 135,428 rows
delivery_idnumber · unique idevent_idtextuser_idnumber · links to usersaccount_idnumber · links to accountssession_idnumber · links to sessionsevent_nametextoccurred_atdate & timereceived_atdate & time
1evt_0000001111user_signed_up2024-01-14 18:52:142024-01-14 18:52:33
2evt_0000002111onboarding_started2024-01-14 18:52:512024-01-14 18:53:06
3evt_00000846232user_signed_up2024-01-15 13:21:522024-01-15 13:22:00
4evt_00000856232onboarding_started2024-01-15 13:22:052024-01-15 13:22:16
5evt_00000866232onboarding_completed2024-01-15 13:23:522024-01-15 13:24:12
6evt_0000019119search_performed2024-01-17 20:56:552024-01-17 20:56:59
delivery_idnumber · unique id
1
event_idtext
evt_0000001
user_idnumber · links to users
1
account_idnumber · links to accounts
1
session_idnumber · links to sessions
1
event_nametext
user_signed_up
occurred_atdate & time
2024-01-14 18:52:14
received_atdate & time
2024-01-14 18:52:33
delivery_idnumber · unique id
2
event_idtext
evt_0000002
user_idnumber · links to users
1
account_idnumber · links to accounts
1
session_idnumber · links to sessions
1
event_nametext
onboarding_started
occurred_atdate & time
2024-01-14 18:52:51
received_atdate & time
2024-01-14 18:53:06
delivery_idnumber · unique id
3
event_idtext
evt_0000084
user_idnumber · links to users
6
account_idnumber · links to accounts
2
session_idnumber · links to sessions
32
event_nametext
user_signed_up
occurred_atdate & time
2024-01-15 13:21:52
received_atdate & time
2024-01-15 13:22:00
delivery_idnumber · unique id
4
event_idtext
evt_0000085
user_idnumber · links to users
6
account_idnumber · links to accounts
2
session_idnumber · links to sessions
32
event_nametext
onboarding_started
occurred_atdate & time
2024-01-15 13:22:05
received_atdate & time
2024-01-15 13:22:16
delivery_idnumber · unique id
5
event_idtext
evt_0000086
user_idnumber · links to users
6
account_idnumber · links to accounts
2
session_idnumber · links to sessions
32
event_nametext
onboarding_completed
occurred_atdate & time
2024-01-15 13:23:52
received_atdate & time
2024-01-15 13:24:12
delivery_idnumber · unique id
6
event_idtext
evt_0000019
user_idnumber · links to users
1
account_idnumber · links to accounts
1
session_idnumber · links to sessions
9
event_nametext
search_performed
occurred_atdate & time
2024-01-17 20:56:55
received_atdate & time
2024-01-17 20:56:59

first 6 of 135,428 rows · your queries use all of them

worked example

Run these steps in order to see the idea before you write your own query. The step marked “the pattern” is what the challenges ask for. Running the example does not count toward progress.

  1. Find event_ids with retries. Run this. deliveries > 1 means the pipeline delivered the same logical event more than once.the pattern

    example.sql
    SELECT event_id, COUNT(*) AS deliveries
    FROM events
    GROUP BY event_id
    HAVING COUNT(*) > 1
    LIMIT 10;
  2. Open one retried event. Run this. You see every delivery row for a single event_id—same occurred_at, different delivery_id and received_at.

    step-2.sql
    SELECT delivery_id, event_id, event_name, occurred_at, received_at
    FROM events
    WHERE event_id = (
      SELECT event_id
      FROM events
      GROUP BY event_id
      HAVING COUNT(*) > 1
      LIMIT 1
    );
  3. Rank deliveries per event. Run this. ROW_NUMBER() ordered by received_at marks the earliest delivery as 1—that is the copy you keep for analytics.

    step-3.sql
    SELECT
      event_id,
      delivery_id,
      received_at,
      ROW_NUMBER() OVER (PARTITION BY event_id ORDER BY received_at, delivery_id) AS delivery_rank
    FROM events
    WHERE event_id IN (
      SELECT event_id
      FROM events
      WHERE occurred_at >= '2025-05-01' AND occurred_at < '2025-05-02'
      GROUP BY event_id
      HAVING COUNT(*) > 1
    )
    ORDER BY event_id, delivery_rank;

common mistake

COUNT(*) on the raw table counts deliveries, not events. Retries inflate every metric built on it.

challenge 1

For events that occurred in June 2025, keep one delivery per event_id (the earliest received, ties by lowest delivery_id) and return delivery_id, event_id, user_id and event_name.

what to return

Columns
delivery_idevent_iduser_idevent_name in this order
Rows
any order
challenge-1.sql
 
To master this lesson, solve both challenges without hints and pass the concept check. 3 of 3 to go.
Deduplicate event retries — Advanced product analysis · Runtime