題目
Table: Spending
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| user_id | int |
| spend_date | date |
| platform | enum |
| amount | int |
+-------------+---------+
The table logs the history of the spending of users that make purchases from an online shopping website that has a desktop and a mobile application.
(user_id, spend_date, platform) is the primary key of this table.
The platform column is an ENUM type of ('desktop', 'mobile').
Write an SQL query to find the total number of users and the total amount spent using the mobile only, the desktop only, and both mobile and desktop together for each date.
Return the result table in any order.
SQL Schema
Create table If Not Exists Spending (user_id int, spend_date date, platform ENUM('desktop', 'mobile'), amount int)
Truncate table Spending
insert into Spending (user_id, spend_date, platform, amount) values ('1', '2019-07-01', 'mobile', '100')
insert into Spending (user_id, spend_date, platform, amount) values ('1', '2019-07-01', 'desktop', '100')
insert into Spending (user_id, spend_date, platform, amount) values ('2', '2019-07-01', 'mobile', '100')
insert into Spending (user_id, spend_date, platform, amount) values ('2', '2019-07-02', 'mobile', '100')
insert into Spending (user_id, spend_date, platform, amount) values ('3', '2019-07-01', 'desktop', '100')
insert into Spending (user_id, spend_date, platform, amount) values ('3', '2019-07-02', 'desktop', '100')
解題思考
- 題目要求統計透過用戶
user在使用PCdesktop、手機APPmobile以及兩者皆有both的採購金額amount。
分開計算PCdesktop和手機APPmobile並不困難,因此需要著手處理的是兩者皆有both採購紀錄的用戶,並將這些用戶從PCdesktop和手機APPmobile的統計中分離出來。 - 透過
with clause建立p_user_platform表格,從spending表格帶出user_id、spend_date,並透過group by user_id, spend_date將資料分組為每個用戶user_id在每個spend_date的採購資料,並分開加總platform="mobile"、platform="desktop"的採購數量amount以賦予mobild_amount和desktop_amount欄位。 - 透過
with clause建立p_user_summary表格,判斷mobild_amount和desktop_amount的值,將每位用戶在每個spend_date的採購情形分類成desktop、mobile和both
這個步驟也可以在建立p_user_platform的過程中進行分類,但我傾向明確每張表格的用途,以便理解每一個query statement中引用的資料表格與欄位。 - 透過
with clause建立p_spend_date表格,並在spending表格擷取所有不重複的spend_date,並將每個不重複的spend_date擴展成帶有desktop、mobile和both的 record 。
這個動作會將每個不重複的spend_date,從原先的 1 row 擴展成 3 rows。 - 透過查詢
p_spend_date作為主要表格,使用left join p_user_summary帶出相對應spend_date、platform的 record set,並利用spend_date、platform統計出該spend_date在desktop、mobile和both的總採購量total_amount和總計人數total_user。
解決方案
with
p_user_platform as (
select
user_id, spend_date,
sum(case when platform = 'mobile' then amount else 0 end) as mobile_amount,
sum(case when platform = 'desktop' then amount else 0 end) as desktop_amount
from spending
group by user_id, spend_date
),
p_user_summary as (
select
user_id, spend_date,
if(mobile_amount > 0, if(desktop_amount > 0, 'both', 'mobile'), 'desktop') as platform,
mobile_amount + desktop_amount as amount
from p_user_platform
),
p_spend_date 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
)
select
a.spend_date, a.platform,
sum(ifnull(b.amount,0)) as total_amount,
count(b.user_id) as total_users
from p_spend_date a
left join p_user_summary b using(spend_date, platform)
group by a.spend_date, a.platform