我有一个表,记录用户在网站上的登录信息,包括ID和登录日期。
例如:
id | 用户ID | 日期 |
---|---|---|
1 | 1234 | 2024-01-01 |
2 | 2341 | 2024-01-07 |
3 | 2341 | 2024-01-13 |
4 | 3412 | 2024-01-20 |
5 | 4123 | 2024-01-20 |
6 | 4123 | 2024-01-21 |
7 | 4123 | 2024-01-22 |
8 | 2341 | 2024-01-07 |
9 | 2341 | 2024-01-22 |
10 | 3412 | 2024-01-20 |
11 | 4123 | 2024-01-20 |
12 | 4123 | 2024-01-21 |
13 | 4123 | 2024-01-22 |
14 | 2341 | 2024-01-23 |
15 | 2341 | 2024-01-25 |
16 | 3412 | 2024-01-20 |
请注意,该表将包含重复数据,因为用户可能每天登录多次。
我现在想计算用户的平均次日留存率,对于上面的示例数据,平均次日留存率为0.3。
我尝试了以下查询,但得到的结果是0.4。我觉得我的想法应该是对的,但是不知道为什么结果是错的。
任何人都可以帮我找出问题所在或给我正确的答案吗? (我使用PieCloudDB数据库,如果你没有听说过,可以使用PostgreSQL代替。PieCloudDB与PostgreSQL兼容)
SELECT COUNT(DISTINCT (q2.user_id,q2.date))*1.0/COUNT(DISTINCT (q1.user_id,q1.date)) as avg_ret
from login as q1
left join login as q2
on q1.user_id=q2.user_id
and q2.date = q1.date + interval '1 day'
我尝试分别对id和日期进行重复数据删除,得到的结果是0.3。 (在pieclouddb数据库云平台测试)
SELECT COUNT(q2.user_id)*1.0 / COUNT(q1.user_id) AS avg_ret
FROM (SELECT DISTINCT user_id, date
FROM login) AS q1
LEFT JOIN (SELECT DISTINCT user_id, date
FROM login) AS q2
ON q1.user_id = q2.user_id
AND q2.date = q1.date + interval '1 day'
该错误是由
COUNT(DISTINCT q2.user_id, q2.date)
引起的,包括 NULL, NULL
作为不同组合之一。以下查询产生正确的结果 0.3:
SELECT
COUNT(DISTINCT (q2.user_id, q2.date))
FILTER (WHERE q2.date IS NOT NULL) * 1.0
/
COUNT(DISTINCT (q1.user_id, q1.date)) AS avg_ret
FROM
login AS q1
LEFT JOIN login AS q2
ON q1.user_id = q2.user_id
AND q2.date = q1.date + INTERVAL '1 day';
解决此问题的一个选择是避免
LEFT JOIN
并使用 CASE
和 EXISTS
逻辑:
WITH login_sub AS
(SELECT
DISTINCT user_id, login_date
FROM login)
SELECT
COUNT(CASE WHEN EXISTS
(SELECT 1 FROM login_sub l2
WHERE
login_sub.user_id = l2.user_id
AND login_sub.login_date + interval '1 day' = l2.login_date)
THEN 1 END) * 1.0 / COUNT(*) AS avg_ret
FROM login_sub;
此查询返回 0.3,请参阅此 样本小提琴 以及您的数据