cswork / libraryOpen practice workspace

Coding questions · OPPO

Solve three SQL problems (easy/medium/hard)

This question evaluates proficiency in SQL data manipulation including aggregation, window functions for rolling calculations, temporal joins, and gaps-and-islands analysis across increasing difficulty levels.

Answer the following SQL tasks of increasing difficulty:

  1. Aggregation: Given Orders(order_id, customer_id, amount, order_date), return each customer's total spend and order count for Jan 1–Dec 31, 2024, sorted by total spend descending.
  2. Windowing: Given Transactions(id, user_id, amount, created_at), compute for each user the 7-day rolling sum of amount for every calendar date present in the data, emitting dates with zero activity where needed.
  3. Advanced joins and gaps-islands: Given Sessions(user_id, start_time, end_time) and Memberships(user_id, plan, activated_at, canceled_at), find users who had any session time while their membership was inactive (outside [activated_at, canceled_at)), and output user_id and total inactive-session minutes.

Customer aggregation: total spend and order count in 2024

Given an Orders table with (order_id, customer_id, amount, order_date), return each customer's total spend and order count for orders placed from 2024-01-01 through 2024-12-31 (inclusive). Output columns: customer_id, total_spend, order_count. Sort by total_spend descending, then customer_id ascending.

Table orders

columntypeconstraints
order_idINTPRIMARY KEY, NOT NULL
customer_idINTNOT NULL
amountDECIMAL(10,2)NOT NULL
order_dateDATENOT NULL

Sample data:

amountcustomer_idorder_dateorder_id
501012024-01-101
251012024-03-052
1001022024-02-143
751032024-12-314
251032024-07-045
401022023-12-316
601012025-01-017

Expected output

One row per customer who has at least one order in calendar year 2024, showing total spend and order count for that year.

customer_idorder_counttotal_spend
1021100
1032100
101275

Hints

  1. Filter by the 2024 date range before aggregating.
  2. Use SUM(amount) and COUNT(*) grouped by customer_id.

7-day rolling sum per user with zero-activity dates

Given Transactions(id, user_id, amount, created_at), compute for each user the 7-day rolling sum of amount for every calendar date between the minimum and maximum transaction dates in the table (inclusive). You must emit a row for each (user_id, date) pair in that global date range, including dates where the user has zero transactions. The 7-day window is the current date plus the previous 6 calendar days. Output columns: user_id, activity_date, rolling_7d_amount. Order by user_id, activity_date.

Assume rolling sums are based on daily totals (i.e., sum amounts per user per day first, then apply the rolling window).

Table transactions

columntypeconstraints
idINTPRIMARY KEY, NOT NULL
user_idINTNOT NULL
amountDECIMAL(10,2)NOT NULL
created_atTIMESTAMPNOT NULL

Sample data:

amountcreated_atiduser_id
102025-05-20 10:00:0011
52025-05-22 12:00:0021
72025-05-25 09:00:0031
32025-05-21 08:00:0042
42025-05-24 15:00:0052
22025-05-24 18:00:0062

Expected output

For each user and each calendar date in the global date range (2025-05-20 to 2025-05-25), show the rolling 7-day sum of daily amounts (including the current date). Dates with no user activity must appear with daily total = 0 and still contribute to the rolling window.

activity_daterolling_7d_amountuser_id
2025-05-20101
2025-05-21101
2025-05-22151
2025-05-23151
2025-05-24151
2025-05-25221
2025-05-2002
2025-05-2132
2025-05-2232
2025-05-2332
2025-05-2492
2025-05-2592

Hints

  1. Generate a calendar from MIN(created_at::date) to MAX(created_at::date).
  2. Cross join users to the calendar to force zero-activity dates, then left join daily totals.
  3. Use a window SUM with ROWS BETWEEN 6 PRECEDING AND CURRENT ROW.

Inactive membership session minutes (joins + time overlap)

Given Sessions(user_id, start_time, end_time) and Memberships(user_id, plan, activated_at, canceled_at), find users who had any session time while their membership was inactive.

A membership is active on the half-open interval [activated_at, canceled_at). If canceled_at is NULL, treat the membership as active indefinitely into the future.

For each user, compute the total number of minutes spent in sessions during inactive time (i.e., session time not covered by any active membership interval). Output columns: user_id, inactive_session_minutes.

Assume memberships for a given user do not overlap each other in time. Sessions may partially overlap membership windows.

Order by user_id ascending.

Table sessions

columntypeconstraints
session_idINTPRIMARY KEY, NOT NULL
user_idINTNOT NULL
start_timeTIMESTAMPNOT NULL
end_timeTIMESTAMPNOT NULL

Sample data:

end_timesession_idstart_timeuser_id
2025-02-15 11:00:0012025-02-15 10:00:001
2025-03-10 09:30:0022025-03-10 09:00:001
2025-01-10 10:45:0032025-01-10 10:00:002
2025-04-01 00:30:0042025-03-31 23:30:002
2025-05-15 13:00:0052025-05-15 12:00:003
2025-05-25 12:20:0062025-05-25 12:00:003

Table memberships

columntypeconstraints
membership_idINTPRIMARY KEY, NOT NULL
user_idINTNOT NULL
planVARCHAR(20)NOT NULL
activated_atTIMESTAMPNOT NULL
canceled_atTIMESTAMP

Sample data:

activated_atcanceled_atmembership_idplanuser_id
2025-01-01 00:00:002025-02-01 00:00:001basic1
2025-03-01 00:00:00NULL2pro1
2025-01-15 00:00:002025-04-01 00:00:003basic2
2025-05-01 00:00:002025-05-20 00:00:004basic3

Expected output

One row per user who has > 0 minutes of session time outside all active membership intervals, with total inactive minutes summed across all sessions (including partial overlaps).

inactive_session_minutesuser_id
601
752
203

Hints

  1. Compute session duration, then subtract the overlapped time with membership intervals.
  2. Use GREATEST(start_time, activated_at) and LEAST(end_time, canceled_at) to compute overlap.
  3. Remember the membership interval is half-open: [activated_at, canceled_at), and treat NULL canceled_at as 'infinite'.