要获得“每周平均用户”计数(根据我对您的规范的理解......“对于每一天,当天和前六天看到的不同 user_id 的计数”),查询如下可以使用下面的一个。 (该查询还返回“每日平均用户”计数。
SELECT d.day
, COUNT(DISTINCT u.user_id) AS wau
, COUNT(DISTINCT IF(u.day=d.day,u.user_id,NULL)) AS dau
FROM ( SELECT FLOOR(k.ts/86400) AS `day`
FROM `log` k
GROUP BY `day`
) d
JOIN ( SELECT FLOOR(l.ts/86400) AS `day`
, l.user_id
FROM `log` l
GROUP BY `day`, l.user_id
) u
ON u.day <= d.day
AND u.day > d.day - 7
GROUP BY d.day
ORDER BY d.day
(我还没有对此进行测试;但我稍后会进行测试,如果需要任何更正,我会更新此声明。)
此查询将给定日期(来自u 行源)的用户列表加入到日志表(d 行源)中的一组日期。请注意连接谓词(ON 子句)中出现的文字“7”,这就是使用户列表与前 6 天“匹配”的原因。
请注意,这也可以扩展以获取过去 3 天的不同用户计数,例如,通过在 SELECT 列表中添加另一个表达式。
, COUNT(DISTINCT IF(u.day<=d.day AND u.day>d.day-3,u.user_id,NULL)) AS 3day
文字“7”可以增加以获得更大的范围。上面表达式中的文字 3 可以更改为任意天数......我们只需要确保我们有足够的前一天行(来自d)加入到来自u的每一行。
性能说明:由于内联视图(或 MySQL 所称的派生表),此查询可能不会很快,因为这些内联视图的结果集必须具体化到中间 MyISAM 表中。
别名为u 的内联视图可能不是最佳的;直接加入日志表可能会更快。我正在考虑获取给定日期的唯一用户列表,这就是内联视图中的查询让我得到的。我更容易概念化正在发生的事情。而且我在想,如果一天中有数百个相同的用户输入,那么在我们加入其他日子之前,内联视图会清除一大堆重复项。
最好在 u 和 d 内联视图中添加 WHERE 子句来限制我们返回的天数。 (d 内联视图需要包含额外的前 6 天。)
另一方面,如果 ts 列是 TIMESTAMP 数据类型,我会更倾向于使用 DATE(ts) 表达式来提取日期部分。但这会在结果集中返回 DATE 数据类型,而不是整数,这与您指定的结果集不同。)
SELECT d.day
, COUNT(DISTINCT u.user_id) AS wau
, COUNT(DISTINCT IF(u.day=d.day,u.user_id,NULL)) AS dau
FROM ( SELECT DATE(k.ts) AS `day`
FROM `log` k
GROUP BY `day`
) d
JOIN ( SELECT DATE(l.ts) AS `day`
, l.user_id
FROM `log` l
GROUP BY `day`, l.user_id
) u
ON u.day <= d.day
AND u.day > DATE_ADD(d.day, INTERVAL -7 DAY)
GROUP BY d.day
ORDER BY d.day