怎樣把一張三個字段的表統計出花來:SQL在分類或按時間統計時,補全缺失的分類或時間

前幾天,有一個業務,這個業務是統計每個月的累計用戶數量,用於做大屏展示使用。

爲了省去前端的開發時間,大屏展示使用了開源工具davinci,該工具集成了echarts報表,可以通過編寫SQL,選擇圖表類型,拖動和縮放圖表生成自己的報表或大屏頁面。

但是這樣就導致了不能在查詢出結果後,不能對數據進行二次加工;另外我們本次連的是業務庫,我們只有查詢權限,這就封禁了建中間表的方式。所以只能在SQL上下功夫了。

以下是我所有sql的迭代過程。

1、數據庫簡化模型

t_user用戶表簡化模型如下:

user_name user_type create_month
張一 1 2020-05
張二 1 2020-05
張三 1 2020-04
張四 1 2020-03
李一 2 2020-05
李二 2 2020-04
李三 2 2020-02

2、按類型分組查詢每月新增用戶

使用如下sql統計每個月,每個類型的用戶新增人數。

SELECT
	user_type,
	create_month,
	count( 1 ) AS cnt 
FROM
	t_user 
GROUP BY
	user_type,
	create_month

查詢結果如下

user_type create_month cnt
1 2020-03 1
1 2020-04 1
1 2020-05 2
2 2020-02 1
2 2020-04 1
2 2020-05 1

3、初級進階:按類型分組查詢每個月累計用戶

使用如下sql統計每個月,每個類型的用戶累計用戶數。

SELECT
	user_type,
	create_month,
	(
	SELECT
		sum( cnt ) 
	FROM
		( SELECT user_type, create_month, count( 1 ) cnt 
		FROM t_user GROUP BY user_type, create_month ) b 
	WHERE
		b.create_month <= a.create_month 
		AND b.user_type = a.user_type 
	) AS total 
FROM
	t_user a 
GROUP BY
	user_type,
	create_month

查詢結果如下

user_type create_month total
1 2020-03 1
1 2020-04 2
1 2020-05 4
2 2020-02 1
2 2020-04 2
2 2020-05 3

4、中級進階:在3的基礎上添加一個彙總的分類

在案例 3 基礎上,彙總每個月的 1 類和 2 類用戶爲 3 。

SELECT
	user_type,
	create_month,
	(
	SELECT
		sum( cnt ) 
	FROM
		( SELECT user_type, create_month, count( 1 ) cnt 
		FROM t_user GROUP BY user_type, create_month ) b 
	WHERE
		b.create_month <= a.create_month 
		AND b.user_type = a.user_type 
	) AS total 
FROM
	t_user a 
GROUP BY
	user_type,
	create_month UNION ALL
SELECT
	3 AS user_type,
	create_month,
	(
	SELECT
		sum( cnt ) 
	FROM
		( SELECT create_month, count( 1 ) cnt FROM t_user GROUP BY create_month ) b 
	WHERE
		b.create_month <= a.create_month 
	) AS total 
FROM
	t_user a 
GROUP BY
	create_month

查詢結果如下

user_type create_month total
1 2020-03 1
1 2020-04 2
1 2020-05 4
2 2020-02 1
2 2020-04 2
2 2020-05 3
3 2020-02 1
3 2020-03 2
3 2020-04 4
3 2020-05 7

5、高級進階:在3的基礎上補全缺失的月份

在案例 3 的基礎上,把分類 1 和 2 的缺失月份的數據補全爲 0。
思路爲:先把分類和月份做全連接,這樣就可以得出分類和月的所有排列組合;然後把數量對應到所在的分類和月份,沒有數量的使用 ifnull(total, 0) 補全爲 0。

SELECT
	b.user_type,
	b.create_month,
	ifnull( a.total, 0 ) AS total 
FROM
	(
	SELECT
		user_type,
		create_month,
		(
		SELECT
			sum( cnt ) 
		FROM
			( SELECT user_type, create_month, count( 1 ) cnt 
			FROM t_user GROUP BY user_type, create_month ) b 
		WHERE
			b.create_month <= a.create_month 
			AND b.user_type = a.user_type 
		) AS total 
	FROM
		t_user a 
	GROUP BY
		user_type,
		create_month 
	) a
	RIGHT JOIN (
	SELECT
		* 
	FROM
		( SELECT user_type FROM t_user GROUP BY user_type ) a
		LEFT JOIN ( SELECT create_month FROM t_user GROUP BY create_month ) b ON 1 = 1 
	) b ON a.user_type = b.user_type 
	AND a.create_month = b.create_month 
ORDER BY
	b.user_type,
	b.create_month

查詢結果如下

user_type create_month total
1 2020-02 0
1 2020-03 1
1 2020-04 2
1 2020-05 4
2 2020-02 1
2 2020-03 0
2 2020-04 2
2 2020-05 3

6、變態進階:在3的基礎上既補全缺失的月份,又添加彙總分類

把 4 和 5 結合起來,就可以兼顧補全缺失的月份和添加彙總分類。

SELECT
	b.user_type,
	b.create_month,
	ifnull( a.total, 0 ) AS total 
FROM
	(
	SELECT
		user_type,
		create_month,
		(
		SELECT
			sum( cnt ) 
		FROM
			( SELECT user_type, create_month, count( 1 ) cnt 
			FROM t_user GROUP BY user_type, create_month ) b 
		WHERE
			b.create_month <= a.create_month 
			AND b.user_type = a.user_type 
		) AS total 
	FROM
		t_user a 
	GROUP BY
		user_type,
		create_month 
	) a
	RIGHT JOIN (
	SELECT
		* 
	FROM
		( SELECT user_type FROM t_user GROUP BY user_type ) a
		LEFT JOIN ( SELECT create_month FROM t_user GROUP BY create_month ) b ON 1 = 1 
	) b ON a.user_type = b.user_type 
	AND a.create_month = b.create_month UNION ALL
SELECT
	3 AS user_type,
	create_month,
	(
	SELECT
		sum( cnt ) 
	FROM
		( SELECT create_month, count( 1 ) cnt FROM t_user GROUP BY create_month ) b 
	WHERE
		b.create_month <= a.create_month 
	) AS total 
FROM
	t_user a 
GROUP BY
	create_month 
ORDER BY
	user_type,
	create_month

查詢結果如下

user_type create_month total
1 2020-02 0
1 2020-03 1
1 2020-04 2
1 2020-05 4
2 2020-02 1
2 2020-03 0
2 2020-04 2
2 2020-05 3
3 2020-02 1
3 2020-03 2
3 2020-04 4
3 2020-05 7

7、總結

任何一個複雜需求都可以拆分成簡單的需求。

就像這個需求,如果一開始就讓我知道最終的SQL會這麼複雜,那我肯定繞道了。

🐒吼吼~~

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