Leetcode1127. 用户购买平台

题目
支出表: Spending

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| user_id     | int     |
| spend_date  | date    |
| platform    | enum    | 
| amount      | int     |
+-------------+---------+

这张表记录了用户在一个在线购物网站的支出历史,该在线购物平台同时拥有桌面端('desktop')和手机端('mobile')的应用程序。
这张表的主键是 (user_id, spend_date, platform)。
平台列 platform 是一种 ENUM ,类型为('desktop', 'mobile')。

写一段 SQL 来查找每天 仅 使用手机端用户、仅 使用桌面端用户和 同时 使用桌面端和手机端的用户人数和总支出金额。

查询结果格式如下例所示:

Spending table:

+---------+------------+----------+--------+
| user_id | spend_date | platform | amount |
+---------+------------+----------+--------+
| 1       | 2019-07-01 | mobile   | 100    |
| 1       | 2019-07-01 | desktop  | 100    |
| 2       | 2019-07-01 | mobile   | 100    |
| 2       | 2019-07-02 | mobile   | 100    |
| 3       | 2019-07-01 | desktop  | 100    |
| 3       | 2019-07-02 | desktop  | 100    |
+---------+------------+----------+--------+

Result table:

+------------+----------+--------------+-------------+
| spend_date | platform | total_amount | total_users |
+------------+----------+--------------+-------------+
| 2019-07-01 | desktop  | 100          | 1           |
| 2019-07-01 | mobile   | 100          | 1           |
| 2019-07-01 | both     | 200          | 1           |
| 2019-07-02 | desktop  | 100          | 1           |
| 2019-07-02 | mobile   | 100          | 1           |
| 2019-07-02 | both     | 0            | 0           |
+------------+----------+--------------+-------------+ 

在 2019-07-01, 用户1 同时 使用桌面端和手机端购买, 用户2 仅 使用了手机端购买,而用户3 仅 使用了桌面端购买。
在 2019-07-02, 用户2 仅 使用了手机端购买, 用户3 仅 使用了桌面端购买,且没有用户 同时 使用桌面端和手机端购买。

生成数据

# 建表语句

CREATE TABLE Spending (
  user_id INT,
  spend_date DATE,
  platform ENUM ('desktop', 'mobile'),
  amount INT
) ;

# 插入测试数据
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) ; 
INSERT INTO Spending ( user_id, spend_date, platform, amount ) VALUES (3, '2019-07-03', 'desktop', 100) ; 

解答
对user_id、 spend_date进行分组 统计 platform的数量

SELECT S.`user_id`, S.`spend_date`, COUNT(DISTINCT S.`platform`) AS num
FROM Spending AS S
GROUP BY S.`user_id`, S.`spend_date`;

数量超过两个的即为both 计算一下分组的amount和

SELECT S.`user_id`, S.`spend_date`, 
IF(COUNT(DISTINCT S.`platform`) = 1, S.`platform`, 'both') AS platform,
SUM(S.`amount`) AS amount
FROM Spending AS S
GROUP BY S.`user_id`, S.`spend_date`;

对于上表 对时间和platform进行分组统计数量 得到 total_users

SELECT tmp.`spend_date`, tmp.`platform`, SUM(tmp.amount) AS amount, COUNT(tmp.user_id) 
FROM (SELECT S.`user_id`, S.`spend_date`, 
IF(COUNT(DISTINCT S.`platform`) = 1, S.`platform`, 'both') AS platform,
SUM(S.`amount`) AS amount
FROM Spending AS S
GROUP BY S.`user_id`, S.`spend_date`) AS tmp
GROUP BY tmp.`spend_date`, tmp.`platform`

但是题目要求不存在也要放在结果里面,只是结果置0而已。

一个想法就是把所有日期和三个类型的组合先写出来 这里用笛卡尔乘积即可

SELECT A.`spend_date`, B.`platform`
FROM (SELECT DISTINCT S.`spend_date`
FROM Spending AS S) AS A, 
(SELECT 'desktop' AS platform UNION
 SELECT 'mobile' AS platform UNION
 SELECT 'both' AS platform
) AS B;

所有存在的结果和之前的结果进行左连接

SELECT all_res.spend_date, all_res.platform, res.amount, res.total_users
FROM (SELECT A.`spend_date`, B.`platform`
FROM (SELECT DISTINCT S.`spend_date`
FROM Spending AS S) AS A, 
(SELECT 'desktop' AS platform UNION
 SELECT 'mobile' AS platform UNION
 SELECT 'both' AS platform
) AS B) AS all_res
LEFT JOIN (SELECT tmp.`spend_date`, tmp.`platform`, SUM(tmp.amount) AS amount, COUNT(tmp.user_id) AS  total_users
FROM (SELECT S.`user_id`, S.`spend_date`, 
IF(COUNT(DISTINCT S.`platform`) = 1, S.`platform`, 'both') AS platform,
SUM(S.`amount`) AS amount
FROM Spending AS S
GROUP BY S.`user_id`, S.`spend_date`) AS tmp
GROUP BY tmp.`spend_date`, tmp.`platform`) AS res
ON all_res.spend_date = res.spend_date AND all_res.platform = res.platform

将null转为0 即可

SELECT all_res.spend_date, all_res.platform, IFNULL(res.amount, 0) AS amount, 
IFNULL(res.total_users,0) AS total_users
FROM (SELECT A.`spend_date`, B.`platform`
FROM (SELECT DISTINCT S.`spend_date`
FROM Spending AS S) AS A, 
(SELECT 'desktop' AS platform UNION
 SELECT 'mobile' AS platform UNION
 SELECT 'both' AS platform
) AS B) AS all_res
LEFT JOIN (SELECT tmp.`spend_date`, tmp.`platform`, SUM(tmp.amount) AS amount, COUNT(tmp.user_id) AS  total_users
FROM (SELECT S.`user_id`, S.`spend_date`, 
IF(COUNT(DISTINCT S.`platform`) = 1, S.`platform`, 'both') AS platform,
SUM(S.`amount`) AS amount
FROM Spending AS S
GROUP BY S.`user_id`, S.`spend_date`) AS tmp
GROUP BY tmp.`spend_date`, tmp.`platform`) AS res
ON all_res.spend_date = res.spend_date AND all_res.platform = res.platform
GROUP BY all_res.spend_date, all_res.platform;

你可能感兴趣的:(Leetcode1127. 用户购买平台)