mysql按日期分組(group by)查詢統計的時候,沒有資料補0的解決辦法。
寫部落格真實個費時費力的差事,好佩服那些部落格閱讀幾十上百萬的人。今天研究了半天按照日期分組統計,沒有資料就為空了,我要讓他顯示0呀。想了辦法,都沒有找到一個好的,解決方案,然後用了一個很low的方法實現了,還是把它記錄下來。方法是用於mysql,與開發語言無關。
1、案例中的資料結構和資料如下
2、在沒有解決的時候,是這樣的
SELECT date(downtime) AS dday, count(*) AS num FROM re_device GROUP BY dday
得到如下結果,如果那天沒有資料,那麼就會沒有記錄
我們看到,時間不連續,沒有2016-3-05這一天的
簡單的說就是,沒有資料,就要補充一個0.
3、下面我們講實現
我們要生成一個日曆的表,然後和原來的資料,聯合查詢,說到這裡,大家就知道很low了,但是,限於我水平有限,研究這個問題,半天,這個是我找到的比較好的一種實現方式。如果你又更好的,也請你給我說下。
執行下面的sql,直接誒生成日曆的表(calendar)
CREATE TABLE num (i int);-- 建立一個表用來儲存0-9的數字
INSERT INTO num (i) VALUES (0), (1), (2 ), (3), (4), (5), (6), (7), (8), (9);-- 生成0-9的數字,方便以後計算時間
CREATE TABLE if not exists calendar(datelist date); -- 生成一個儲存日期的表,datalist是欄位名
-- 這裡是生成並插入日期資料
INSERT INTO calendar(datelist) SELECT
adddate(
( -- 這裡的起始日期,你可以換成當前日期
DATE_FORMAT("2016-1-1", '%Y-%m-%d')
),
numlist.id
) AS `date`
FROM
(
SELECT
n1.i + n10.i * 10 + n100.i * 100 + n1000.i * 1000+ n10000.i * 10000 AS id
FROM
num n1
CROSS JOIN num AS n10
CROSS JOIN num AS n100
CROSS JOIN num AS n1000
CROSS JOIN num AS n10000
) AS numlist;
這裡我用了100000條記錄,算出來到2289年了,完全夠用了,到那個時候,出問題,我也管不了了。
完成之後,請刪除num的零時表
4、聯合查詢
SELECT
date(dday) ddate,
count(*) - 1 as num
FROM
(
SELECT
datelist as dday
FROM
calendar
-- 這裡是限制返回最近30天的資料
where DATE_SUB(CURDATE(), INTERVAL 30 DAY) <= date(datelist)&&date(datelist)<=CURDATE()
UNION ALL
SELECT
downtime
FROM
re_device
) a
GROUP BY ddate
好了,到這裡,基本就完成了這個查詢,出來的資料,我還是比較滿意的。
5、其他解決方法
當然,應該還有其他的解決方案,但是博主就沒有去寫了,有時間可以去寫一下。
我用的spring mvc,所以,也還是可以在java程式碼中補充完整的,因為資料返回的是個map物件,那麼我們要遍歷這個物件,直接用calendar物件,生成日期作為key來遍歷,如果沒有資料,就put進去一個0,然後在限制一下,需要多少天的,就可以了。資料就完整了。
但是這樣也有一個問題,那就是map裡的資料順序會有問題,所以,使用的時候,也必須是生成calendar物件,然後構造出來日期作為key來遍歷。或者用Collections.sort()排序一下。
我個人覺得,還是上資料直接生成得比較好一點。