cswork / libraryOpen practice workspace

Coding questions · Meta

Write SQL for revenue and advertiser analyses

This question evaluates a candidate's proficiency in SQL data manipulation and analytics, including aggregation, joins, date-range filtering, handling missing-period values, distinct counts, and proportional calculations within the Data Manipulation (SQL/Python) domain.

Use the schema below and ANSI SQL. Treat “today” as 2025-09-01. Schema:

  • active_ads(date DATE, ad_id INT, advertiser_id INT, creation_source VARCHAR, revenue DECIMAL(12,2))
  • advertiser_info(advertiser_id INT, advertiser_name VARCHAR, advertiser_country VARCHAR) Sample rows (minimal, for clarity):
active_ads
date | ad_id | advertiser_id | creation_source | revenue
2025-08-30 | 101 | 1 | web | 120.00
2025-08-30 | 102 | 1 | api | 80.00
2025-08-31 | 103 | 2 | web | 0.00
2025-09-01 | 104 | 3 | mobile | 200.00
2025-09-01 | 105 | 2 | web | 50.00
advertiser_info
advertiser_id | advertiser_name | advertiser_country
1 | Acme | US
2 | Globex | CA
3 | Initech | US

Tasks:

  1. Daily revenue by creation_source: Return date, creation_source, daily_revenue where daily_revenue = SUM(revenue) over all ads for that source on that date. Order by date, creation_source. Include only dates present in active_ads.
  2. Ten countries with the fewest active advertisers in the last 30 days: Define an “active advertiser” as one with at least one active_ads row with revenue > 0 and date between 2025-08-03 and 2025-09-01 inclusive. Return the 10 countries (from advertiser_info) with the smallest count of distinct active advertisers, including countries with zero active advertisers (show count 0). Break ties by advertiser_country alphabetically. Output columns: advertiser_country, active_advertiser_count.
  3. Growth proportion by creation_source: For each creation_source, compute the proportion of advertisers whose spend in 2025-01-01..2025-09-01 exceeds their spend in 2024-01-01..2024-09-01 by at least 1000. Denominator = number of advertisers who had any spend (>0) in either period for that same creation_source. Output: creation_source, num_grew_by_1000, denom, proportion (rounded to 4 decimals). Provide a single query (CTEs allowed) that handles advertisers present in only one of the two periods by treating missing-period spend as 0.

Daily Revenue by Creation Source

You are given two tables: active_ads and advertiser_info.

Table: active_ads

  • date (DATE): calendar date of the ad impression.
  • ad_id (INT): unique identifier for the ad.
  • advertiser_id (INT): identifier for the advertiser that owns the ad.
  • creation_source (VARCHAR): channel where the ad was created (e.g., 'web', 'api', 'mobile').
  • revenue (DECIMAL): revenue generated by that ad on that date.

Table: advertiser_info

  • advertiser_id (INT): unique identifier for the advertiser.
  • advertiser_name (VARCHAR): name of the advertiser.
  • advertiser_country (VARCHAR): country of the advertiser.

Task: Return the daily revenue by creation_source. For each (date, creation_source) pair, compute daily_revenue = SUM(revenue) over all ads for that creation_source on that date. Return columns:

  • date
  • creation_source
  • daily_revenue

Include only dates that appear in active_ads. Order the result by date ascending, then creation_source ascending.

Table active_ads

columntypeconstraints
dateDATENOT NULL
ad_idINTPRIMARY KEY
advertiser_idINTNOT NULL
creation_sourceVARCHAR(20)NOT NULL
revenueDECIMAL(12,2)NOT NULL

Sample data:

ad_idadvertiser_idcreation_sourcedaterevenue
10011web2024-02-10500
10024web2024-04-15400
10031api2024-05-20300
10045api2024-06-10200
10052mobile2024-07-01100
10063mobile2024-07-10600
10078mobile2024-07-201200
20013mobile2025-03-10600
20021web2025-05-051000
20032web2025-05-10900
20041api2025-05-15300
20057web2025-05-18500
20064web2025-05-20300
20076mobile2025-05-28800
20082mobile2025-05-301300
20093api2025-06-151500
20104web2025-08-30200
20115api2025-09-0150

Table advertiser_info

columntypeconstraints
advertiser_idINTPRIMARY KEY
advertiser_nameVARCHAR(100)NOT NULL
advertiser_countryVARCHAR(50)NOT NULL

Sample data:

advertiser_countryadvertiser_idadvertiser_name
US1Acme
CA2Globex
US3Initech
UK4Umbrella
DE5Hooli
IN6Soylent
BR7MassiveDynamic
FR8Vehement
AU9WayneEnterprises
JP10StarkIndustries
MX11Wonka

Expected output

One row per (date, creation_source) showing the total revenue on that date for that creation_source, ordered by date then creation_source.

creation_sourcedaily_revenuedate
web5002024-02-10
web4002024-04-15
api3002024-05-20
api2002024-06-10
mobile1002024-07-01
mobile6002024-07-10
mobile12002024-07-20
mobile6002025-03-10
web10002025-05-05
web9002025-05-10
api3002025-05-15
web5002025-05-18
web3002025-05-20
mobile8002025-05-28
mobile13002025-05-30
api15002025-06-15
web2002025-08-30
api502025-09-01

Hints

  1. Group by both date and creation_source.
  2. Use SUM(revenue) and order by date then creation_source.

Countries with Fewest Active Advertisers in a 30-Day Window

Using the same active_ads and advertiser_info tables as described, define an "active advertiser" as one that has at least one row in active_ads with revenue > 0 and date between 2025-05-03 and 2025-06-01 inclusive.

Task: Find the 10 advertiser countries (from advertiser_info) with the smallest number of distinct active advertisers in that window. Include countries that have zero active advertisers in this period (show active_advertiser_count = 0).

Output columns:

  • advertiser_country
  • active_advertiser_count (the count of distinct advertisers from that country that are active in the given window)

Order the result by active_advertiser_count ascending, and for ties order alphabetically by advertiser_country. Return only the first 10 rows after sorting.

Table active_ads

columntypeconstraints
dateDATENOT NULL
ad_idINTPRIMARY KEY
advertiser_idINTNOT NULL
creation_sourceVARCHAR(20)NOT NULL
revenueDECIMAL(12,2)NOT NULL

Sample data:

ad_idadvertiser_idcreation_sourcedaterevenue
10011web2024-02-10500
10024web2024-04-15400
10031api2024-05-20300
10045api2024-06-10200
10052mobile2024-07-01100
10063mobile2024-07-10600
10078mobile2024-07-201200
20013mobile2025-03-10600
20021web2025-05-051000
20032web2025-05-10900
20041api2025-05-15300
20057web2025-05-18500
20064web2025-05-20300
20076mobile2025-05-28800
20082mobile2025-05-301300
20093api2025-06-151500
20104web2025-08-30200
20115api2025-09-0150

Table advertiser_info

columntypeconstraints
advertiser_idINTPRIMARY KEY
advertiser_nameVARCHAR(100)NOT NULL
advertiser_countryVARCHAR(50)NOT NULL

Sample data:

advertiser_countryadvertiser_idadvertiser_name
US1Acme
CA2Globex
US3Initech
UK4Umbrella
DE5Hooli
IN6Soylent
BR7MassiveDynamic
FR8Vehement
AU9WayneEnterprises
JP10StarkIndustries
MX11Wonka

Expected output

Ten countries with the smallest number of distinct active advertisers in the window 2025-05-03 to 2025-06-01 (inclusive), including countries with zero active advertisers. Sorted by count ascending, then country ascending.

active_advertiser_countadvertiser_country
0AU
0DE
0FR
0JP
0MX
1BR
1CA
1IN
1UK
1US

Hints

  1. First find the distinct active advertiser_ids in the date window using a CTE or subquery.
  2. Left join advertiser_info to the active set and count DISTINCT advertiser_id per country, then order by the count and country and limit to 10.

Growth Proportion by Creation Source Across Years

Using the same active_ads and advertiser_info tables, analyze advertiser spend by creation_source across two periods:

  • Period 1: 2024-01-01 to 2024-09-01 (inclusive)
  • Period 2: 2025-01-01 to 2025-09-01 (inclusive)

For each advertiser and creation_source, define:

  • revenue_2024 = total revenue in Period 1 for that advertiser and creation_source.
  • revenue_2025 = total revenue in Period 2 for that advertiser and creation_source.

An advertiser is considered to have "grown by at least 1000" for a given creation_source if:

  • revenue_2025 - revenue_2024 >= 1000

For each creation_source, compute:

  • num_grew_by_1000: number of advertisers whose spend grew by at least 1000 for that creation_source.
  • denom: number of advertisers who had any positive spend (revenue > 0) in EITHER period for that creation_source.
  • proportion: num_grew_by_1000 / denom, rounded to 4 decimal places.

Advertisers that are present in only one of the two periods for a given creation_source should be treated as having 0 revenue in the missing period.

Task: Write a single SQL query (you may use CTEs) that returns, for each creation_source:

  • creation_source
  • num_grew_by_1000
  • denom
  • proportion (rounded to 4 decimal places)

Order the result by creation_source ascending.

Table active_ads

columntypeconstraints
dateDATENOT NULL
ad_idINTPRIMARY KEY
advertiser_idINTNOT NULL
creation_sourceVARCHAR(20)NOT NULL
revenueDECIMAL(12,2)NOT NULL

Sample data:

ad_idadvertiser_idcreation_sourcedaterevenue
10011web2024-02-10500
10024web2024-04-15400
10031api2024-05-20300
10045api2024-06-10200
10052mobile2024-07-01100
10063mobile2024-07-10600
10078mobile2024-07-201200
20013mobile2025-03-10600
20021web2025-05-051000
20032web2025-05-10900
20041api2025-05-15300
20057web2025-05-18500
20064web2025-05-20300
20076mobile2025-05-28800
20082mobile2025-05-301300
20093api2025-06-151500
20104web2025-08-30200
20115api2025-09-0150

Table advertiser_info

columntypeconstraints
advertiser_idINTPRIMARY KEY
advertiser_nameVARCHAR(100)NOT NULL
advertiser_countryVARCHAR(50)NOT NULL

Sample data:

advertiser_countryadvertiser_idadvertiser_name
US1Acme
CA2Globex
US3Initech
UK4Umbrella
DE5Hooli
IN6Soylent
BR7MassiveDynamic
FR8Vehement
AU9WayneEnterprises
JP10StarkIndustries
MX11Wonka

Expected output

For each creation_source, the number of advertisers whose revenue increased by at least 1000 from 2024-01-01..2024-09-01 to 2025-01-01..2025-09-01, the total number of advertisers with positive spend in either period for that source, and the resulting proportion.

creation_sourcedenomnum_grew_by_1000proportion
api310.3333
mobile410.25
web400

Hints

  1. First aggregate revenue per advertiser_id, creation_source, and period using conditional SUM with CASE on the date ranges.
  2. In a second aggregation, per creation_source, count advertisers whose revenue_2025 - revenue_2024 >= 1000 and divide by the number with positive spend in either period; use CASE to handle missing periods as 0.