刷刷题,leetcode的550题。
表定义如下:
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| player_id | int |
| device_id | int |
| event_date | date |
| games_played | int |
+--------------+---------+
(player_id,event_date)是此表的主键(具有唯一值的列的组合)。
这张表显示了某些游戏的玩家的活动情况。
每一行是一个玩家的记录,他在某一天使用某个设备注销之前登录并玩了很多游戏(可能是 0)。
编写解决方案,报告在首次登录的第二天再次登录的玩家的 比率,四舍五入到小数点后两位。换句话说,你需要计算从首次登录日期开始至少连续两天登录的玩家的数量,然后除以玩家总数。
初次一看题目,使用左连接left join ,把用户id和日期作为关联条件,再去重。简单写出第一版语句:
SELECT ROUND(
(SELECT COUNT(distinct a.player_id) FROM activity a
join activity b
on a.player_id = b.player_id
and a.event_date = ADDDATE(b.event_date, 1))
/
(SELECT COUNT(DISTINCT player_id) FROM activity)
,2) fraction ;
自信满满的提交,满心期待绿色的通过。结果很很打脸了,测试案例第6个没过。
老老实实把案例数据搞下来,跑跑看。
想用ai工具,把这个.md案例数据转成sql,失败了。可能是数据量太大了。
好吧,那就自己编码转成sql吧。
public void Case550()
{
var mdfile = @"D:\xxx\LeetCodeCase\case550\case6.md";
var sqlfile = @"D:\xxx\LeetCodeCase\case550\case6.sql";
var mdTxtArr = File.ReadAllLines(mdfile);
var sqlBuilder = new StringBuilder();
sqlBuilder.AppendLine("INSERT INTO Activity (player_id, device_id, event_date, games_played) VALUES");
foreach (var item in mdTxtArr)
{
var arr = item.Trim('|').Split('|');
if (arr.Length >= 4)
{
var val = #34;({arr[0].Trim()}, {arr[1].Trim()}, '{arr[2].Trim()}', {arr[3].Trim()}),";
sqlBuilder.AppendLine(val);
}
}
var sqlTxt = sqlBuilder.ToString();
File.WriteAllText(sqlfile, sqlTxt);
}
把结果导进去后,再仔细读题目。发现自己漏了关键信息“首次登录”。整理思路,先把首次登录的用户和日期筛选出来,再关联原表,把结果相除。代码如下:
SELECT ROUND( COUNT(distinct t.player_id) / COUNT(distinct tb.player_id),2) fraction
FROM (
SELECT player_id
,MIN(event_date) first_date
FROM activity
GROUP BY player_id
) AS tb
LEFT JOIN activity t
ON tb.player_id = t.player_id
AND tb.first_date = ADDDATE(t.event_date, -1)
再次提交,成功。