The Campaign Trail

An easy SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.

Domain
SQL
Difficulty
easy
Seniority
L3
Asked in
Uber

Problem

The ad_impressions table logs every ad shown along with the revenue it earned, so a campaign's money is spread across many rows. Return the campaigns whose revenue booked through the end of June 2026 adds up to more than $4.50, listed alphabetically by name.

Impressions are vanity. Conversions are sanity.

Tables

ad_impressions

Columns: impression_id INTEGER, user_id INTEGER, ad_campaign TEXT, impression_time TEXT, clicked INTEGER, revenue REAL

ad_impressions: 10 of 200 rows
impression_iduser_idad_campaignimpression_timeclickedrevenue
253100BRAND_AWARENESS_Q12026-02-02 01:07:000NULL
306197PRODUCT_LAUNCH_X2026-03-03 02:14:000NULL
359294RETARGETING_CART2026-04-04 03:21:000NULL
412391HOLIDAY_PROMO2026-05-05 04:28:000NULL
465488NEW_USER_ACQU2026-06-06 05:35:0010.2
518NULLLOYALTY_PROGRAM2026-07-07 06:42:000NULL
571682FLASH_SALE_48H2026-08-08 07:49:000NULL
624779SUMMER_SALE_20242026-09-09 08:56:000NULL
677876BRAND_AWARENESS_Q12026-01-10 09:03:000NULL
730973PRODUCT_LAUNCH_X2026-02-11 10:10:0010.35

Expected output

First 4 of 4 rows
ad_campaign
FLASH_SALE_48H
LOYALTY_PROGRAM
PRODUCT_LAUNCH_X
SUMMER_SALE_2024

Worked solution and explanation

This is a filter-the-total problem wearing a renewal-review costume. Each campaign's money is scattered across a few clicked impressions worth a couple of dollars apiece, and no single row on this data earns more than $3.75, so the $4.50 bar is a property of the campaign's sum, never of an impression. Anyone can write the grouping. What separates candidates is judging the bar after the totals exist while keeping the June cutoff in front of them. Put the bar in WHERE revenue > 4.5 and the list comes back empty. Drop the cutoff and 'HOLIDAY_PROMO' sneaks in on July money it had not earned yet.

Three moves, in the order the engine runs them

Step 1: Cut the timeline at June 2026

impression_time is ISO text, so strftime('%Y-%m', impression_time) yields a 'YYYY-MM' key that compares correctly as a string. Keep rows <= '2026-06'. This belongs before the grouping because it decides which rows a total is made of.

Step 2: Total each campaign

Group by ad_campaign and take SUM(revenue). Unclicked impressions carry NULL revenue and SUM skips them, which is exactly the business meaning: they earned nothing.

Step 3: Judge the total, then sort

HAVING SUM(revenue) > 4.5 runs once per campaign, after the sum exists. It is strictly greater, so a campaign at exactly $4.50 stays out. Finish with ORDER BY ad_campaign; the names are one per group, so the order is fully decided.

Cut, total, then judge the total
SELECT ad_campaign
FROM ad_impressions
WHERE strftime('%Y-%m', impression_time) <= '2026-06'
GROUP BY ad_campaign
HAVING SUM(revenue) > 4.5
ORDER BY ad_campaign
Bar on each impression
WHERE revenue > 4.5 asks whether one impression earned $4.50. None did; the largest single row is $3.75, so the answer is an empty list.
Bar on each campaign
HAVING SUM(revenue) > 4.5 asks whether the campaign earned $4.50 in total. 'PRODUCT_LAUNCH_X' gets there with $5.00 from four rows, none of them above $2.75.

Common follow-up questions