mysql查询连续时间数据——无数据补0

用D3来画统计图,数据是从mysql数据库中查出来的。

统计图是关于某段时间内,每年/每月/每周的微博数量的折线图。数据表是一条微博为一条记录,每条记录有日期这个字段。

首先考虑用group by来统计每天/ 每月/每年的微博数量,但是这样就会有一个问题:如果某天没有数据,也就是没有发微博,那么group by的结果是没有这一天的,也就是说我们group by 的结果永远不会有0。显然这样的结果是不对的。

那么如何解决这个问题呢,思路就是要补全没有的日期,然后在这个日期对应的数量字段填0。

下面看一下具体的实现。


第一步:如何补全没有的日期

最直接的方法就是我手动产生一个连续的日期。代码是这样的:(也是网上参考别人的代码)

<span style="font-size:12px;">CREATE TABLE num (i int);
INSERT INTO num (i) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);
select adddate('2012-09-01', numlist.id) as `date` from (SELECT n1.i + n10.i*10 + n100.i*100 AS id FROM num n1 cross join num as n10 cross join num as n100) as numlist where adddate('2012-09-01', numlist.id) <= '2012-09-10';</span>
结果:


可以看到产生了指定时间的连续日期。我们现在要的是,从某个账号发的第一条微博到现在的时间,所以修改相应的代码,成这样:

(对了,讲一下,刚开始把num表误起名为month,所以以后就叫month了)

<span style="font-size:12px;">select adddate(( SELECT DATE_FORMAT( wi.PubTime, '%Y-%m-%d') as weibo_date
FROM weibo_info_copy as wi where wi.UID='1705822647' and wi.PubTime > 0
GROUP BY DATE_FORMAT( wi.PubTime, '%Y-%m-%d' )
limit 1), numlist.id) as `date` from (SELECT n1.i + n10.i*10 + n100.i*100+n1000.i*1000 AS id FROM month n1 cross join month as n10 cross join month as n100 cross join month as n1000) as numlist where adddate(( SELECT DATE_FORMAT( wi.PubTime, '%Y-%m-%d') as weibo_date
FROM weibo_info_copy as wi where wi.UID='1705822647'
GROUP BY DATE_FORMAT( wi.PubTime, '%Y-%m-%d' )
limit 1), numlist.id) <= CURRENT_DATE</span>

修改了三处:

(1)起始时间:这里用了一个sql语句的查询结果,就是微博数据的第一条的时间。这样防止了不同账号相同的起始时间反映在图表上会造成很长的空白或者是漏掉一部分数据。

(2)终止时间:这里选取当前时间

(3)范围:“注意到之前的数量只会到1000,这里多加了一部分,数量会扩大到10000,算了一下27年有余,应该是够用了。

这样就可以产生一个连续的日期:


可以看到,从2010-03-06到现在,有2190天。

好了,现在我们完成了第一步,得到了连续的时间。


第二步:将结果存入表格,以便联合查询。

这里用到insert into语句。

<span style="font-size:12px;">drop table if exists weibo_line_date;
CREATE TABLE  if not exists weibo_line_date (name date);
insert into weibo_line_date (name) select * from (
select adddate(( SELECT DATE_FORMAT( wi.PubTime, '%Y-%m-%d') as weibo_date
FROM weibo_info_copy as wi where wi.UID='1705822647' and wi.PubTime > 0
GROUP BY DATE_FORMAT( wi.PubTime, '%Y-%m-%d' )
limit 1), numlist.id) as `date` from (SELECT n1.i + n10.i*10 + n100.i*100+n1000.i*1000 AS id FROM month n1 cross join month as n10 cross join month as n100 cross join month as n1000) as numlist where adddate(( SELECT DATE_FORMAT( wi.PubTime, '%Y-%m-%d') as weibo_date
FROM weibo_info_copy as wi where wi.UID='1705822647'
GROUP BY DATE_FORMAT( wi.PubTime, '%Y-%m-%d' )
limit 1), numlist.id) <= CURRENT_DATE
) as t</span>

注意到两点:

(1)先要删除原来的表,为了不重复添加数据

(2)在建表时指定数据类型和字符集,不然会出错。

好了,现在可以得到一个如上结果的新表,叫做weibo_line_date。


第三步:联合查询,无数据补0

<span style="font-size:12px;">SELECT weibo_line_date.name as weibo_date, IF(weibo_num IS NULL , 0, weibo_num) as weibo_num
FROM(SELECT DATE_FORMAT( wi.PubTime, '%Y-%m-%d') as weibo_date , COUNT(*) as weibo_num
	FROM weibo_info_copy as wi where wi.UID='1705822647'
	GROUP BY DATE_FORMAT( wi.PubTime, '%Y-%m-%d' )) t
RIGHT JOIN weibo_line_date on t.weibo_date = weibo_line_date.name </span>

结果:


这就得到了我想要的结果。

看一下图吧



这样就完成了我们的需求。



拓展一下,如果查每年/每月的,又该怎么办呢。

首先想到,我们要产生一个连续的月份的表。修改代码:

select date_format(date_add((SELECT DATE_FORMAT( wi.PubTime, '%Y-%m-%d') as weibo_date
FROM weibo_info_copy as wi where wi.UID='1705822647'
GROUP BY DATE_FORMAT( wi.PubTime, '%Y-%m' )
limit 1), interval numlist.id month),'%Y-%m') as `date` 
from (SELECT n1.i + n10.i*10 + n100.i*100 AS id FROM month n1 cross join month as n10 cross join month as n100) as numlist 
where date_format(date_add((SELECT DATE_FORMAT( wi.PubTime, '%Y-%m-%d') as weibo_date
FROM weibo_info_copy as wi where wi.UID='1705822647'
GROUP BY DATE_FORMAT( wi.PubTime, '%Y-%m' )
limit 1), interval numlist.id month),'%Y-%m') <= date_format(CURRENT_DATE,'%Y-%m')

注意两个地方:

(1)数据格式:我们现在要的是2010-03这样的数据,所以要用data_format函数,将‘0000-00-00‘的数据转换为’0000-00‘

(2)间隔:date_add函数,第一个参数是起始时间;第二个参数是间隔,如果为整数,就默认为间隔一天,现在我们要设置为一个月,

interval numlist.id month
要写成这样。如果是一年就是year


其次,在新建表的时候,如果指定字段类型为date会出错,结果全为’0000-00‘,所以我改为了text。

这样的话,在下一步联合查询的时候,字符集不匹配会报错,所以要指定相应的字符集。这里一定要注意。

CREATE TABLE  if not exists weibo_line_date (name text  CHARACTER SET UTF8)


接下来的步骤就和之前的一样了。



©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页