我有一个 user
表,其中包含标准列 id
和 registered_date
对于一年中的每一周(例如 DATE_FORMAT '%x-%v' ),我想要统计该周过去 4 周内注册的用户数(包括该周本身)。
例如,对于 2014-50 周,我想要计算在第 50 周以及第 49、48 和 47 周注册的用户数。
通常,要统计每周的注册用户数,我会使用:
SELECT DATE_FORMAT(registered_date, '%x-%v'), count(*)
FROM user
GROUP BY DATE_FORMAT(registered_date, '%x-%v')
当然,这也不包括在过去 3 周内注册的用户。
知道如何相应地修改查询吗?
最佳答案
我们将不得不创建一个结构化查询来获取这些内容。
首先,我们需要一个子查询来生成用户注册每周开始日期的列表。我们需要星期一的日期,因为您正在使用 %x-%v
获取周数。
要获取紧接在任何 DATETIME
值之前的星期一的日期,可以使用此表达式。
DATE(registered_date) - INTERVAL WEEKDAY(registered_date) DAY
所以这个小子查询为我们提供了星期一的列表。
SELECT DISTINCT DATE(registered_date) -
INTERVAL WEEKDAY(registered_date) DAY as monday
FROM user
接下来,我们需要将其嵌套在另一个查询中,以便为每个(重叠的)四个星期的时间段获取一行,我们希望对其进行汇总。每行将包含三列:期间的第一个日期、期间的最后+1 日期和期间的标识符,例如“2013-52”。
SELECT monday - INTERVAL 3 WEEK AS start,
monday + INTERVAL 1 WEEK AS finish,
DATE_FORMAT(monday, '%x-%v') AS week
FROM (
SELECT DISTINCT DATE(registered_date) -
INTERVAL WEEKDAY(registered_date) DAY as monday
FROM user
) AS wks
很酷。现在我们有了一个表,我们可以将它与 user
表结合起来,以提取哪些用户在哪个时期注册。我们可以这样做
SELECT user.id, periods.week
FROM user
JOIN ( /* the subquery */
) AS periods ON user.registered_date >= periods.start
AND user.registered_date < periods.finish
但我们不想要那个细节,而是想要计数,所以我们将其重写为聚合查询。
SELECT periods.week, COUNT(*)
FROM user
JOIN ( /* the subquery */
) AS periods ON user.registered_date >= periods.start
AND user.registered_date < periods.finish
GROUP BY periods.week
ORDER BY periods.week
将所有内容放在一起,这是查询。
SELECT periods.week, COUNT(*)
FROM user
JOIN (
SELECT monday - INTERVAL 3 WEEK AS start,
monday + INTERVAL 1 WEEK AS finish,
DATE_FORMAT(monday, '%x-%v') AS week
FROM (
SELECT DISTINCT DATE(registered_date) -
INTERVAL WEEKDAY(registered_date) DAY as monday
FROM user
) AS wks
) AS periods ON user.registered_date >= periods.start
AND user.registered_date < periods.finish
GROUP BY periods.week
ORDER BY periods.week
这看起来像一个毛球,但请注意,我们把它做成了一个三明治,由相当简单的部分组成。
将用户分配到适当的 4 周时间段的技巧已嵌入此加入的 ON 条件中。
ON user.registered_date >= periods.start
AND user.registered_date < periods.finish
由于开始日期和结束日期重叠,每个用户都被分配到多个 4 周的时间段。
这里的另一个技巧是使用实际日期而不是周 ID“2014-45”进行计算,因为不可能将周 ID 转换回日期,尤其是在年末,我们希望使用计算像 date - INTERVAL 3 WEEK
来计算开始和结束日期。
关于mysql - SQL 按相对日期范围分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27660525/