cswork / libraryOpen practice workspace

Coding questions · Upstart

Manipulate data in R with dplyr joins and windows

This question evaluates proficiency in R data manipulation with dplyr, specifically joins, window functions, date filtering, aggregation, and handling edge cases like refunds and first-purchase identification.

Using R and dplyr, answer the following using these small tables (dates are ISO strings):

transactions(user_id, order_id, order_date, channel, amount)
 u1 | o1 | 2025-08-28 | web | 120
 u1 | o2 | 2025-09-03 | web | 80
 u2 | o3 | 2025-09-01 | store | 50
 u3 | o4 | 2025-09-01 | web | 60
 u3 | o5 | 2025-09-10 | store | 40
refunds(order_id, refund_date, amount)
 o2 | 2025-09-05 | 80
 o5 | 2025-09-12 | 20
users(user_id, signup_date)
 u1 | 2025-08-20
 u2 | 2025-08-30
 u3 | 2025-09-01

Tasks: 1) Compute net revenue per day and channel between 2025-09-01 and 2025-09-10 inclusive, where net revenue = purchases minus refunds that occur on or before 2025-09-10. 2) For each user, identify first_purchase_date and a flag fully_refunded_first_purchase (1 if the first order was fully refunded by 2025-09-10). 3) Compute a 3-day rolling sum of net revenue by channel over that window (aligned to the right). 4) Produce a tidy data frame with columns (date, channel, net_revenue, rolling3_net_revenue) and another with (user_id, first_purchase_date, fully_refunded_first_purchase). Write idiomatic dplyr code (no loops), handling joins, windowing, and edge cases correctly.

Daily Net Revenue and 3-Day Rolling Sum by Channel

You are given three tables: transactions, refunds, and users. Using standard SQL, compute net revenue per calendar day and channel between 2025-09-01 and 2025-09-10 inclusive, where net revenue is defined as purchase amounts minus refund amounts that occur on or before 2025-09-10. Assume that refunds reduce revenue on the refund_date, and use the channel of the original order for each refund.

Requirements:

  1. For each channel that appears in the transactions table, generate a row for every calendar date from 2025-09-01 through 2025-09-10, even if there are no purchases or refunds on that day for that channel. On such days, net_revenue should be 0.
  2. Compute a 3-day rolling sum of net revenue by channel, aligned to the right: for each date D and channel C, rolling3_net_revenue is the sum of net_revenue for channel C over dates from max(2025-09-01, D-2 days) through D.
  3. Return a result with columns (date, channel, net_revenue, rolling3_net_revenue).

Write a single SQL query that produces this result.

Table transactions

columntypeconstraints
user_idVARCHAR(10)NOT NULL
order_idVARCHAR(10)PRIMARY KEY, NOT NULL
order_dateDATENOT NULL
channelVARCHAR(20)NOT NULL
amountDECIMAL(10,2)NOT NULL

Sample data:

amountchannelorder_dateorder_iduser_id
120web2025-08-28o1u1
80web2025-09-03o2u1
50store2025-09-01o3u2
60web2025-09-01o4u3
40store2025-09-10o5u3

Table refunds

columntypeconstraints
order_idVARCHAR(10)NOT NULL
refund_dateDATENOT NULL
amountDECIMAL(10,2)NOT NULL

Sample data:

amountorder_idrefund_date
80o22025-09-05
20o52025-09-12

Table users

columntypeconstraints
user_idVARCHAR(10)PRIMARY KEY, NOT NULL
signup_dateDATENOT NULL

Sample data:

signup_dateuser_id
2025-08-20u1
2025-08-30u2
2025-09-01u3

Expected output

For each calendar date from 2025-09-01 to 2025-09-10 and for each channel present in the transactions table, the result contains the net revenue (purchases minus refunds on that date) and the 3-day rolling sum of net revenue for that channel up to that date. Days without activity for a given channel have net_revenue = 0 but still appear, and rolling3_net_revenue is computed over those zeros.

channeldatenet_revenuerolling3_net_revenue
store2025-09-015050
web2025-09-016060
store2025-09-02050
web2025-09-02060
store2025-09-03050
web2025-09-0380140
store2025-09-0400
web2025-09-04080
store2025-09-0500
web2025-09-05-800
store2025-09-0600
web2025-09-060-80
store2025-09-0700
web2025-09-070-80
store2025-09-0800
web2025-09-0800
store2025-09-0900
web2025-09-0900
store2025-09-104040
web2025-09-1000

Hints

  1. Aggregate purchases and refunds by date and channel separately, then join them to compute daily net revenue.
  2. Generate the full date range with a recursive CTE (or date series) and use a window function with ROWS BETWEEN 2 PRECEDING AND CURRENT ROW for the 3-day rolling sum.

First Purchase Date and Fully Refunded Flag per User

Using the same transactions, refunds, and users tables, write a SQL query that, for each user, identifies:

  1. first_purchase_date: the date of their earliest order (by order_date).
  2. fully_refunded_first_purchase: a flag equal to 1 if that first order was fully refunded by 2025-09-10 (i.e., the sum of refund amounts for that order with refund_date <= 2025-09-10 is greater than or equal to the original order amount), otherwise 0.

Include all users from the users table, even if they have no purchases (in which case first_purchase_date may be NULL and the flag should be 0). Return columns (user_id, first_purchase_date, fully_refunded_first_purchase).

Table transactions

columntypeconstraints
user_idVARCHAR(10)NOT NULL
order_idVARCHAR(10)PRIMARY KEY, NOT NULL
order_dateDATENOT NULL
channelVARCHAR(20)NOT NULL
amountDECIMAL(10,2)NOT NULL

Sample data:

amountchannelorder_dateorder_iduser_id
120web2025-08-28o1u1
80web2025-09-03o2u1
50store2025-09-01o3u2
60web2025-09-01o4u3
40store2025-09-10o5u3

Table refunds

columntypeconstraints
order_idVARCHAR(10)NOT NULL
refund_dateDATENOT NULL
amountDECIMAL(10,2)NOT NULL

Sample data:

amountorder_idrefund_date
80o22025-09-05
20o52025-09-12

Table users

columntypeconstraints
user_idVARCHAR(10)PRIMARY KEY, NOT NULL
signup_dateDATENOT NULL

Sample data:

signup_dateuser_id
2025-08-20u1
2025-08-30u2
2025-09-01u3

Expected output

One row per user, showing the date of their first purchase and a flag indicating whether that first purchase was fully refunded by 2025-09-10. In the sample data, no user's first purchase is fully refunded by that date, so all flags are 0.

first_purchase_datefully_refunded_first_purchaseuser_id
2025-08-280u1
2025-09-010u2
2025-09-010u3

Hints

  1. Use a window function like ROW_NUMBER() partitioned by user to identify each user's first order.
  2. Aggregate refunds by order_id with a date filter (refund_date <= 2025-09-10) and compare the summed refund amount to the first order amount.