Question
In the first week after a customer joins the program (including their join date) they earn 2x points on all items, not just sushi - how many points do customer A and B have at the end of January?
Solution
WITH sales_annotated_with_first_week_check AS (
SELECT sales.customer_id,
order_date,
menu.product_id,
product_name,
price,
join_date,
((sales.order_date < members.join_date + INTERVAL '7 DAYS') AND (sales.order_date >= members.join_date)) is_within_first_week
FROM sales
LEFT OUTER JOIN members ON sales.customer_id = members.customer_id
INNER JOIN menu ON sales.product_id = menu.product_id
WHERE order_date <= '2021-01-31' AND sales.customer_id IN ('A', 'B')
),
sales_with_points_multiplier AS (
SELECT customer_id,
order_date,
product_name,
price,
join_date,
(
CASE is_within_first_week
WHEN TRUE THEN 2
ELSE (
CASE product_name
WHEN 'sushi' THEN 2
ELSE 1
END
)
END
) points_multiplier
FROM sales_annotated_with_first_week_check
)
SELECT customer_id, SUM(price * points_multiplier * 10) AS total_points
FROM sales_with_points_multiplier
GROUP BY customer_id;
customer_id | total_points |
---|---|
A | 1370 |
B | 820 |
Walkthrough
Let’s break this down into multiple sub-problems.
First, we’ll build an intermediate table that just stores whether the sales orders that the customer made are within the first week of them becoming a member (i.e. whether the new membership 2x
point bonus applies).
While we’re there, we’ll also retain sales records only up to January 2021 and for customers A
, and B
.
SELECT sales.customer_id,
order_date,
menu.product_id,
product_name,
price,
members.join_date,
((sales.order_date < members.join_date + INTERVAL '7 DAYS') AND (sales.order_date >= members.join_date)) is_within_first_week
FROM sales
LEFT OUTER JOIN members ON sales.customer_id = members.customer_id
INNER JOIN menu ON sales.product_id = menu.product_id
WHERE order_date <= '2021-01-31' AND sales.customer_id IN ('A', 'B');
customer_id | order_date | product_id | product_name | price | join_date | is_within_first_week |
---|---|---|---|---|---|---|
A | 2021-01-10 | 3 | ramen | 12 | 2021-01-07 | true |
A | 2021-01-11 | 3 | ramen | 12 | 2021-01-07 | true |
A | 2021-01-11 | 3 | ramen | 12 | 2021-01-07 | true |
A | 2021-01-01 | 2 | curry | 15 | 2021-01-07 | false |
A | 2021-01-07 | 2 | curry | 15 | 2021-01-07 | true |
A | 2021-01-01 | 1 | sushi | 10 | 2021-01-07 | false |
B | 2021-01-16 | 3 | ramen | 12 | 2021-01-09 | false |
B | 2021-01-01 | 2 | curry | 15 | 2021-01-09 | false |
B | 2021-01-02 | 2 | curry | 15 | 2021-01-09 | false |
B | 2021-01-04 | 1 | sushi | 10 | 2021-01-09 | false |
B | 2021-01-11 | 1 | sushi | 10 | 2021-01-09 | true |
Next, we’ll determine a points multiplier for these sales based on whether the customer bought Sushi or the order was made within the first week of gaining membership.
WITH sales_annotated_with_first_week_check AS (
SELECT sales.customer_id,
order_date,
menu.product_id,
product_name,
price,
members.join_date,
((sales.order_date < members.join_date + INTERVAL '7 DAYS') AND (sales.order_date >= members.join_date)) is_within_first_week
FROM sales
LEFT OUTER JOIN members ON sales.customer_id = members.customer_id
INNER JOIN menu ON sales.product_id = menu.product_id
WHERE order_date <= '2021-01-31' AND sales.customer_id IN ('A', 'B')
)
SELECT customer_id,
order_date,
product_name,
price,
join_date,
(
CASE is_within_first_week
WHEN TRUE THEN 2
ELSE (
CASE product_name
WHEN 'sushi' THEN 2
ELSE 1
END
)
END
) points_multiplier
FROM sales_annotated_with_first_week_check;
customer_id | order_date | product_name | price | join_date | points_multiplier |
---|---|---|---|---|---|
A | 2021-01-10 | ramen | 12 | 2021-01-07 | 2 |
A | 2021-01-11 | ramen | 12 | 2021-01-07 | 2 |
A | 2021-01-11 | ramen | 12 | 2021-01-07 | 2 |
A | 2021-01-01 | curry | 15 | 2021-01-07 | 1 |
A | 2021-01-07 | curry | 15 | 2021-01-07 | 2 |
A | 2021-01-01 | sushi | 10 | 2021-01-07 | 2 |
B | 2021-01-16 | ramen | 12 | 2021-01-09 | 1 |
B | 2021-01-01 | curry | 15 | 2021-01-09 | 1 |
B | 2021-01-02 | curry | 15 | 2021-01-09 | 1 |
B | 2021-01-04 | sushi | 10 | 2021-01-09 | 2 |
B | 2021-01-11 | sushi | 10 | 2021-01-09 | 2 |
Finally, we’ll SUM
up price * points_multiplier * 10
for these sales records and report it as the total points.
WITH sales_annotated_with_first_week_check AS (
SELECT sales.customer_id,
order_date,
menu.product_id,
product_name,
price,
join_date,
((sales.order_date < members.join_date + INTERVAL '7 DAYS') AND (sales.order_date >= members.join_date)) is_within_first_week
FROM sales
LEFT OUTER JOIN members ON sales.customer_id = members.customer_id
INNER JOIN menu ON sales.product_id = menu.product_id
WHERE order_date <= '2021-01-31' AND sales.customer_id IN ('A', 'B')
),
sales_with_points_multiplier AS (
SELECT customer_id,
order_date,
product_name,
price,
join_date,
(
CASE is_within_first_week
WHEN TRUE THEN 2
ELSE (
CASE product_name
WHEN 'sushi' THEN 2
ELSE 1
END
)
END
) points_multiplier
FROM sales_annotated_with_first_week_check
)
SELECT customer_id, SUM(price * points_multiplier * 10) AS total_points
FROM sales_with_points_multiplier
GROUP BY customer_id;
customer_id | total_points |
---|---|
A | 1370 |
B | 820 |