MySql 根據日期 group by 統計數據並將時間不存在的記錄補全(純 sql ,不建表)

開始

最近同事需要一個根據時間聚合統計數據的查詢結果集,並且最好是可以把沒有記錄的日期也可以補全,我搜索了一下只找到說建立一個日期表然後聯表查詢方法,但是多一張沒用的表,太不優雅了,所以我打算自己試試寫一條sql嘗試將結果查詢出來。

思考

由於需要連續的日期,我們想到可以通過MySQL的DATE_ADD或DATE_SUB來獲得。那麼函數中的type固定用DAY,但是expr我們怎麼生成呢?這時候我們就可以設置一個變量不斷遞增來獲取我們需要天數的日期,這樣連續的日期就完成了,然後我們聯合根據時間 group by 查詢出來的結果集查詢即可。

實踐

有一張 user 表,有 user_id 和 create_time 兩個字段,模擬查詢每天註冊人數,暫定查詢今天起往前20天(示例簡單爲主,具體需求可各自擴展)

  1. 根據時間聚合查出結果集
SELECT
	DATE( u.create_time ) AS create_time,
	count( u.user_id ) AS total
FROM
	`user` u 
GROUP BY
	DATE( u.create_time )
  1. 連續時間查詢的結果集
SET @i :=- 1;
SELECT
	date_format( DATE_SUB( NOW( ), INTERVAL ( @i := @i + 1 ) DAY ), '%Y-%m-%d' ) AS `time` 
FROM
	`user` 
WHERE
	@i <= 20
  1. 聯合 1 和 2 兩個結果集的數據
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`

擴展

在最終語句中:

  1. NOW() 可以替換成你想要的任意時間;
  2. DATE_SUB 表示從 NOW() 時間起往前多少天的連續日期,如果需要往後的連續日期,改爲 DATE_ADD 即可。
  3. 在獲得連續日期的語句中,WHERE 條件中的 @i <= 20 表示連續 20 天的日期,數值可自定義,選擇自己想要查詢的連續時間範圍。

總結

確定好自己想要的結果形式,然後慢慢補全,直至獲得最終的結果,利用分治法的思想,把一個大問題分解成幾個小問題,一步一步解決,最終得出大問題的解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章