前言
這篇文章標題不好取。。。(主要是生成連續的日期),本文關鍵點有:Mysql 獲取指定時間段內的所有日期列表,
Mysql 按照日期分組查詢沒有數據的日期也一並查詢出來。
問題
產品提出一個需求,需要展示這樣的一張折線圖,用來反映指定時間段內網站注冊用戶的增加趨勢,於是需要后端的 JSON 工程師給出對應的接口。
疏忽大意
具體的表結構和數據是這樣的
JSON 工程師不加思索,展開了 CRUD 大法,順手寫下了一個 SQL,不到5分鍾,接口完活,測都沒測試直接給到了前端開發。
select date(t.create_time) as `date`,
count(t.id) as num
from t_user t
group by `date`;
前端拿到數據后開始繪圖,結果畫的圖完全不對啊,因為時間不是連續的。於是反饋到了 JSON 工程師這里。
JSON 工程師一想,哎喲,沒考慮掉某天沒有數據的情況,分組查詢的話,肯定缺少這一天的數據的。
+------------+-----+
| date | num |
+------------+-----+
| 2019-05-06 | 2 |
+------------+-----+
| 2019-05-08 | 2 |
+------------+-----+
| 2019-05-09 | 9 |
+------------+-----+
正確的做法應該是即使某天沒有數據,也填充一個 0 作為記錄值。
修正查詢數據
找到了問題就好辦了,捋了一下邏輯分成了兩步
一、拿到所有日期
2019年09月12日更新
感謝評論區中 @一個小可愛(感覺是個有趣的人哈哈)提出的方法,於是我就來更新一下本文了。最好的方式是在 Java 代碼中處理生成連續的日期,然后創建一個 map 對象,初始化所有的鍵值對的值為 0,然后遍歷查詢出來的按照日期作為 key,之后進行 put 覆蓋默認值即可。
提供一個生成連續日期的方法
public static Set<String> getBetweenDate(String start, String end) {
LocalDate startDate = LocalDate.parse(start);
LocalDate endDate = LocalDate.parse(end);
long between = ChronoUnit.DAYS.between(startDate, endDate);
if (between < 1) {
return Stream.of(start, end).collect(Collectors.toSet());
}
return Stream.iterate(startDate, e -> e.plusDays(1))
.limit(between + 1)
.map(LocalDate::toString)
.collect(Collectors.toSet());
}
public static void main(String[] args) {
Set<String> days = BaseTest.getBetweenDate("2019-08-29", "2019-09-02");
log.info("{}", days);
}
二、按照日期分組查詢
原來的文章可能會造成誤解,已更新掉
按照日期分組查詢,遍歷查詢結果,覆蓋第一步里的時間map的值即可。
結果如下:
+------------+-----+
| date | num |
+------------+-----+
| 2019-05-03 | 0 |
+------------+-----+
| 2019-05-04 | 0 |
+------------+-----+
| 2019-05-05 | 0 |
+------------+-----+
| 2019-05-06 | 2 |
+------------+-----+
| 2019-05-07 | 0 |
+------------+-----+
| 2019-05-08 | 2 |
+------------+-----+
| 2019-05-09 | 9 |
+------------+-----+
順利達到了目的,收工!