cswork / libraryOpen practice workspace

Coding questions · Meta

Rank Ads by Conversion Rate for Top 10 Performers

This question evaluates data manipulation and analytics skills for computing time-windowed ad performance metrics, including aggregations of impressions and revenue, join logic between impression and conversion records, conversion-rate calculation, and ranking.

ad

id | advertiser_id | created_at

1 | 101 | 2023-07-01

2 | 102 | 2023-07-05

3 | 101 | 2023-07-10

impression

id | ad_id | user_id | timestamp

10 | 1 | 555 | 2023-07-11 10:00

11 | 1 | 556 | 2023-07-11 10:05

12 | 2 | 557 | 2023-07-12 09:00

conversion

id | impression_id | revenue | timestamp

100 | 10 | 5.00 | 2023-07-11 10:10

101 | 12 | 10.00 | 2023-07-12 09:15

Scenario

Advertising platform wants to track ad effectiveness over the last 30 days.

Question

Given tables ad, impression and conversion, write SQL to return for every ad_id: total impressions, total conversions, conversion_rate and total_revenue for the past 30 days. Extend the query to rank ads by conversion_rate and return the top 10 performers.

Hints

Think joins (impression → conversion), date filters, group-by ad_id, and safe division for rates.

Top 10 Ads by Conversion Rate in a 30-Day Window

An advertising platform wants to track ad effectiveness between 2025-05-03 and 2025-06-01 (inclusive), representing the most recent 30-day period relative to 2025-06-01.

Given the tables ad, impression, and conversion, write a SQL query that returns, for every ad_id:

  • total_impressions
  • total_conversions
  • conversion_rate (total_conversions / total_impressions, treating 0 impressions as a 0 rate)
  • total_revenue

Only impressions and conversions whose timestamps fall between 2025-05-03 and 2025-06-01 (inclusive) should be counted. Extend the query to rank ads by conversion_rate and return the top 10 performers. If multiple ads have the same conversion_rate, break ties by higher total_revenue, then higher total_impressions, then lower ad_id.

Table ad

columntypeconstraints
idINTEGERPRIMARY KEY, NOT NULL
advertiser_idINTEGERNOT NULL
created_atDATENOT NULL

Sample data:

advertiser_idcreated_atid
1012025-05-011
1022025-05-052
1012025-05-103

Table impression

columntypeconstraints
idINTEGERPRIMARY KEY, NOT NULL
ad_idINTEGERNOT NULL, FOREIGN KEY -> ad.id
user_idINTEGERNOT NULL
timestampTIMESTAMPNOT NULL

Sample data:

ad_ididtimestampuser_id
1102025-05-11 10:00:00555
1112025-05-11 10:05:00556
2122025-05-12 09:00:00557

Table conversion

columntypeconstraints
idINTEGERPRIMARY KEY, NOT NULL
impression_idINTEGERNOT NULL, FOREIGN KEY -> impression.id
revenueDECIMAL(10,2)NOT NULL
timestampTIMESTAMPNOT NULL

Sample data:

idimpression_idrevenuetimestamp
100105.002025-05-11 10:10:00
1011210.002025-05-12 09:15:00

Expected output

One row per ad_id for impressions and conversions occurring between 2025-05-03 and 2025-06-01 (inclusive), with total_impressions, total_conversions, conversion_rate, total_revenue, and a rank. Ranking is by conversion_rate (descending), then total_revenue (descending), then total_impressions (descending), then ad_id (ascending). With the provided sample data (all within this 30-day window), the results are:

ad_idconversion_rateranktotal_conversionstotal_impressionstotal_revenue
2111110.00
10.52125.00
303000.00

Hints

  1. Join impressions to conversions via impression_id to count conversions per ad.
  2. Filter impression.timestamp and conversion.timestamp to be between '2025-05-03' and '2025-06-01'.
  3. Group by ad_id to aggregate counts of impressions, conversions, and total revenue.
  4. Use COUNT(DISTINCT ...) where needed to avoid overcounting due to joins.
  5. Use safe division (e.g., total_conversions / NULLIF(total_impressions, 0)) so ads with zero impressions get a conversion_rate of 0 instead of causing an error.
  6. Use a window function such as RANK() ordered by conversion_rate (and tie-breakers) and then LIMIT 10 to get the top performers.