問題描述
有一個用來記錄每日客戶消耗數據的表 t,它的表結構以下:mysql
字段 | 類型 | 描述 |
---|---|---|
created_day | Date | 消耗日期 |
customer_id | Integer | 客戶ID |
amount | Integer | 消耗金額 |
要求:sql
統計出頭部客戶、腰部客戶、尾部客戶在上個月(2020-06-01 ~ 2020-06-30)的留存狀況。微信
輸出結果的格式:.net
層級 | 客戶數量 | 留存數量 |
---|---|---|
頭部客戶 | ||
腰部客戶 | ||
尾部客戶 |
數據定義:code
- 頭部客戶:上個月消耗金額大於等於 30000 的客戶;
- 腰部客戶:上個月消耗金額在 10000 ~ 30000(不包含 30000) 的客戶;
- 尾部客戶:上個月消耗金額小於 10000 的客戶;
- 留存:最近兩個月(上個月和本月)消耗金額大於 0 的客戶;
- 時間:上個月(2020-06-01 ~ 2020-06-30)、本月(2020-07-01 ~ 2020-07-31)
解決方案
今天這個問題和我上一篇文章裏面的問題很類似,只不過這裏要求多統計一列,所以,解決的思路也差很少。get
下面我將用 CTE 來演示每一個步驟。it
第一步,計算出上個月每一個客戶的消耗金額。編譯
with t1 AS (SELECT customer_id, SUM(amount) AS amount FROM t WHERE created_day BETWEEN '2020-06-01' AND '2020-06-30' GROUP BY customer_id) SELECT * FROM t1
第二步,在第一步的基礎上,統計頭部客戶、腰部客戶、尾部客戶的數量。table
t2 AS (SELECT CASE WHEN amount >= 30000 THEN 1 WHEN amount >= 10000 THEN 2 ELSE 3 END AS customer_level, COUNT(*) AS customter_cnt FROM t1 GROUP BY customer_level) SELECT * FROM t2
在腳本中使用代碼 一、二、3 分別表示頭部客戶、腰部客戶、尾部客戶。class
須要注意的是,在 GROUP BY
子句中使用了 SELECT
子句中的字段別名 customer_level
,這種語法在其它數據中是編譯不經過的。
第三步,計算留存。根據留存的定義,只要客戶在本月中有消耗,就計入留存數。好比客戶 A,A 上個月的消耗金額是 40000,那麼 A 就是頭部客戶,假如 A 在本月的消耗金額大於 0,A 就爲【留存】貢獻了 1 。
咱們在 t1
以後插入表達式 t12
,t12
的腳本以下:
t12 AS (SELECT t1.customer_id, t1.amount, IF(tmp.amount > 0, 1, 0) AS keep_state FROM t1 LEFT JOIN (SELECT customer_id, SUM(amount) AS amount FROM t WHERE created_day BETWEEN '2020-07-01' AND '2020-07-31' GROUP BY customer_id) tmp ON tmp.customer_id = t1.customer_id) SELECT * FROM t12
t12
中的左鏈接也能夠改形成標量子查詢。
完整的 SQL 實現:
with t1 AS (SELECT customer_id, SUM(amount) AS amount FROM t WHERE created_day BETWEEN '2020-06-01' AND '2020-06-30' GROUP BY customer_id), t12 AS (SELECT t1.customer_id, t1.amount, IF(tmp.amount > 0, 1, 0) AS keep_state FROM t1 LEFT JOIN (SELECT customer_id, SUM(amount) AS amount FROM t WHERE created_day BETWEEN '2020-07-01' AND '2020-07-31' GROUP BY customer_id) tmp ON tmp.customer_id = t1.customer_id), t2 AS (SELECT CASE WHEN amount >= 30000 THEN 1 WHEN amount >= 10000 THEN 2 ELSE 3 END AS customer_level, COUNT(*) AS customter_cnt, SUM(keep_state) AS keep_cnt FROM t12 GROUP BY customer_level) SELECT CASE customer_level WHEN 1 THEN '頭部客戶' WHEN 2 THEN '腰部客戶' ELSE '尾部客戶' END AS '層級', customter_cnt AS '客戶數量', keep_cnt AS '留存數量' FROM t2 ORDER BY customer_level
感興趣的朋友能夠嘗試不使用左鏈接或者標量子查詢的寫法,而是隻查一次 t 表就能實現需求。
本文分享自微信公衆號 - SQL實現(gh_684ee9235a26)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。