需求
假设有下列表(user_reg),第一列为id,第二列为注册时间(dt),该表记录了每个id的注册时间
现在要统计每个月初(每个月1日)注册的总用户数,时间顺序排序,结果如下
解决方案
- 统计数量必然要使用分组,因此首先要考虑的问题是如何将本月2日到下月1日之间的数据分到一组。这里使用case when进行判断,当日期大于本月第一天的时候返回下个月第一天,否则不变,即
SELECT
dt,
CASE WHEN dt > DATE_SUB( dt, INTERVAL DAYOFMONTH( dt )- 1 DAY ) THEN DATE_ADD( LAST_DAY( dt ), INTERVAL 1 DAY ) ELSE dt END AS dt1
FROM
user_reg;
这里计算本月第一天时使用当前日期减去当前日期在本月的天数(DAYOFMONTH)-1,计算下月第一天时用本月最后一天(LAST_DAY)加1天,这样dt1相同的时候就是一组的数据。
- 然后再使用group by对dt1进行分组并统计数量,得到如下结果
SELECT
CASE WHEN dt > DATE_SUB( dt, INTERVAL DAYOFMONTH( dt )- 1 DAY ) THEN DATE_ADD( LAST_DAY( dt ), INTERVAL 1 DAY ) ELSE dt END AS dt1,
count(1) as cnt
FROM
user_reg
GROUP BY
dt1;
- 最后就是考虑如何把cnt的值进行统计,即求从最开始到当前行的和,这里使用开窗聚合函数SUM
SELECT
dt1,
sum( cnt ) over ( ORDER BY dt1 rows BETWEEN unbounded preceding AND current ROW ) AS cnt
FROM
(
SELECT
CASE WHEN dt > DATE_SUB( dt, INTERVAL DAYOFMONTH( dt )- 1 DAY ) THEN DATE_ADD( LAST_DAY( dt ), INTERVAL 1 DAY ) ELSE dt END AS dt1,
COUNT( 1 ) AS cnt
FROM
user_reg
GROUP BY
dt1
) t;
通过dt1进行升序排序,对cnt进行求和,求和范围是开始到当前行。