我有一个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周内注册的用户。
知道如何相应地修改查询吗?
答案 0 :(得分:2)
我们必须创建一个结构化查询才能获得这些东西。
首先,我们需要一个子查询,它将生成用户注册的每周开始日期的列表。我们需要星期一的日期,因为您使用%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
接下来,我们需要将此嵌套在另一个查询中,以便为我们希望总结的每个(重叠)四周时段获取一行。每行中都有三列:句点的第一个日期,句点的最后一个日期和期间的标识符,例如' 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
这看起来像毛球,但请注意我们已经把它建成了三明治,相当简单的部分。
将用户分配到适当的四周时段的技巧嵌入在ON的连接条件中。
ON user.registered_date >= periods.start
AND user.registered_date < periods.finish
由于开始日期和结束日期重叠,因此每个用户都被分配到多个四周的时间段。
这里的另一个技巧是使用实际日期而不是周ids&#39; 2014-45&#39;对于计算,因为它不可能,特别是在年末,从周ID转换回日期,我们希望使用像date - INTERVAL 3 WEEK
这样的计算来计算开始和结束日期。