
1127. User Purchase Platform [LeetCode]
Sep 12, 2024
3 min read
(To see the full code, go to my github) Write an SQL query to find the total number of users and the total amount spent using mobile only, desktop only and both mobile and desktop together for each date.
Each user_id can spend on either "mobile" or "desktop" (or both) on a given spend_date. We are specifically interested in distinguishing users who spent on one platform only (mobile or desktop) and those who spent on both platforms.
Spending:
![1127. User Purchase Platform [LeetCode]](https://static.wixstatic.com/media/b635b2_b23d058b29e946249bc7cc2baa123b4d~mv2.png/v1/fill/w_113,h_81,al_c,q_85,usm_0.66_1.00_0.01,blur_2,enc_auto/b635b2_b23d058b29e946249bc7cc2baa123b4d~mv2.png)
Output:
![1127. User Purchase Platform [LeetCode]](https://static.wixstatic.com/media/b635b2_5d850e5cf98748c9949073e3215ca962~mv2.png/v1/fill/w_53,h_32,al_c,q_85,usm_0.66_1.00_0.01,blur_2,enc_auto/b635b2_5d850e5cf98748c9949073e3215ca962~mv2.png)
Solution
We will approach the problem in three comprehensive steps:
Generate a sequence of spend dates and three platforms: desktop, mobile, and both.
Find which users have used both platforms on the same day.
Join the two tables from step 1 and 2 to calculate results.
Let's explore each step in detail.
Step 1: Generate a sequence of spend dates and three platforms: desktop, mobile, and both.
-- Create a Common Table Expression (CTE) to define base spend data by date and platform
WITH BASE AS (
SELECT DISTINCT spend_date, 'desktop' AS platform
FROM Spending
UNION
SELECT DISTINCT spend_date, 'mobile' AS platform
FROM Spending
UNION
SELECT DISTINCT spend_date, 'both' AS platform
FROM Spending
)
![1127. User Purchase Platform [LeetCode]](https://static.wixstatic.com/media/b635b2_1b77c9d0d3d2450486c3bd2921cf3fe1~mv2.png/v1/fill/w_62,h_81,al_c,q_85,usm_0.66_1.00_0.01,blur_2,enc_auto/b635b2_1b77c9d0d3d2450486c3bd2921cf3fe1~mv2.png)
Step 2: Find which users have used both platforms on the same day.
We perform a LEFT JOIN between the Spending table and itself to capture users who used both platforms on the same day. This way we ensure that users who only used one platform have NULL in the S2 columns.
SELECT
*
FROM
Spending S1
-- Self join on oppostie platforms to catch users that used both platforms
LEFT JOIN Spending S2
ON S1.user_id = S2.user_id
AND S1.spend_date = S2.spend_date
AND S1.platform != S2.platform
![1127. User Purchase Platform [LeetCode]](https://static.wixstatic.com/media/b635b2_965d440f17b141168afe537576d49d70~mv2.png/v1/fill/w_45,h_16,al_c,q_85,usm_0.66_1.00_0.01,blur_2,enc_auto/b635b2_965d440f17b141168afe537576d49d70~mv2.png)
Step 3: Join the two tables from step 1 and 2 to calculate results.
We perform a RIGHT JOIN between the above table and our BASE table. The conditions ensure that:
Users who spent on both platforms are counted when BASE.platform = 'both' and S2.user_id IS NOT NULL.
Users who spent on only one platform are counted when S2.user_id IS NULL.
SELECT
*
FROM
Spending S1
-- Self join on oppostie platforms to catch users that used both platforms
LEFT JOIN Spending S2
ON S1.user_id = S2.user_id
AND S1.spend_date = S2.spend_date
AND S1.platform != S2.platform
-- Join the BASE CTE to the Spending table based on two conditions:
RIGHT JOIN BASE B
ON
(
-- Case 1: Join where both platforms ('mobile' and 'desktop') were used on the same date by the same user
B.spend_date = S1.spend_date
AND S2.user_id IS NOT NULL -- Ensure the user has spent on both platforms (S2 is not NULL)
AND B.platform = 'both'
)
OR
(
-- Case 2: Join where only one platform ('mobile' or 'desktop') was used by the user
B.spend_date = S1.spend_date
AND S2.user_id IS NULL -- Ensure the user has spent on only one platform (S2 is NULL)
AND B.platform = S1.platform
)
![1127. User Purchase Platform [LeetCode]](https://static.wixstatic.com/media/b635b2_9fc9a0791f7c4fc8bf3deba91813f61c~mv2.png/v1/fill/w_49,h_16,al_c,q_85,usm_0.66_1.00_0.01,blur_2,enc_auto/b635b2_9fc9a0791f7c4fc8bf3deba91813f61c~mv2.png)
Finally we group by spend_date and platform to compute the total spending and unique user counts for each combination of platform and date.
-- Final query to calculate total amount spent and total users by spend date and platform
SELECT
B.spend_date, -- Spend date
B.platform, -- Platform (mobile, desktop, or both)
ISNULL(SUM(S1.amount), 0) AS total_amount, -- Total amount spent (0 if no spend)
COUNT(DISTINCT S1.user_id) AS total_users -- Total number of distinct users
FROM
Spending S1
-- Self join on oppostie platforms to catch users that used both platforms
LEFT JOIN Spending S2
ON S1.user_id = S2.user_id
AND S1.spend_date = S2.spend_date
AND S1.platform != S2.platform
-- Join the BASE CTE to the Spending table based on two conditions:
RIGHT JOIN BASE B
ON
(
-- Case 1: Join where both platforms ('mobile' and 'desktop') were used on the same date by the same user
B.spend_date = S1.spend_date
AND S2.user_id IS NOT NULL -- Ensure the user has spent on both platforms (S2 is not NULL)
AND B.platform = 'both'
)
OR
(
-- Case 2: Join where only one platform ('mobile' or 'desktop') was used by the user
B.spend_date = S1.spend_date
AND S2.user_id IS NULL -- Ensure the user has spent on only one platform (S2 is NULL)
AND B.platform = S1.platform
)
-- Group the results by spend date and platform to get aggregated data
GROUP BY
B.spend_date, B.platform
ORDER BY
B.spend_date, B.platform;
FinalResult:
![1127. User Purchase Platform [LeetCode]](https://static.wixstatic.com/media/b635b2_ede5e0b23e0b4411a57768e8f4c64536~mv2.png/v1/fill/w_54,h_32,al_c,q_85,usm_0.66_1.00_0.01,blur_2,enc_auto/b635b2_ede5e0b23e0b4411a57768e8f4c64536~mv2.png)