最近同事需要一个根据时间聚合统计数据的查询结果集,并且最好是可以把没有记录的日期也可以补全,我搜索了一下只找到说建立一个日期表然后联表查询方法,但是多一张没用的表,太不优雅了,所以我打算自己试试写一条sql尝试将结果查询出来。
由于需要连续的日期,我们想到可以通过MySQL的DATE_ADD或DATE_SUB来获得。那么函数中的type固定用DAY,但是expr我们怎么生成呢?这时候我们就可以设置一个变量不断递增来获取我们需要天数的日期,这样连续的日期就完成了,然后我们联合根据时间 group by 查询出来的结果集查询即可。
有一张 user 表,有 user_id 和 create_time 两个字段,模拟查询每天注册人数,暂定查询今天起往前20天(示例简单为主,具体需求可各自扩展)
SELECT
DATE( u.create_time ) AS create_time,
count( u.user_id ) AS total
FROM
`user` u
GROUP BY
DATE( u.create_time )
SET @i :=- 1;
SELECT
date_format( DATE_SUB( NOW( ), INTERVAL ( @i := @i + 1 ) DAY ), '%Y-%m-%d' ) AS `time`
FROM
`user`
WHERE
@i <= 20
SET @i :=- 1;
SELECT
x.`time`,
-- IFNULL( d.create_time, x.`time` ) AS `create_time`,
IFNULL( d.total, 0 ) AS total
FROM
(
SELECT
date_format( DATE_SUB( NOW( ), INTERVAL ( @i := @i + 1 ) DAY ), '%Y-%m-%d' ) AS `time`
FROM
`user`
WHERE
@i <= 20
) x
LEFT JOIN
(
SELECT
DATE( u.create_time ) AS create_time,
count( u.user_id ) AS total
FROM
`user` u
GROUP BY
DATE( u.create_time )
) d ON TO_DAYS( x.`time` ) = TO_DAYS( DATE( d.create_time ) )
ORDER BY
x.`time`
在最终语句中:
@i <= 20
表示连续 20 天的日期,数值可自定义,选择自己想要查询的连续时间范围。确定好自己想要的结果形式,然后慢慢补全,直至获得最终的结果,利用分治法的思想,把一个大问题分解成几个小问题,一步一步解决,最终得出大问题的解。