要获得“每周平均用户”计数(根据我对您的规范的理解......“对于每一天,当天和前六天看到的不同 user_ids 的计数”),请按照以下行进行查询可用于。(查询还返回“每日平均用户”计数。
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 表中。
别名为 as 的内联视图u
可能不是最佳的;直接加入日志表可能会更快。我正在考虑获取给定日期的唯一用户列表,这就是内联视图中的查询让我得到的。我更容易概念化正在发生的事情。而且我在想,如果一天有数百个相同的用户输入,那么在我们加入其他日子之前,内联视图会清除一大堆重复项。一个 WHERE 子句来限制我们返回的天数最好添加到u
内d
联视图中。(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