mysql 常見統計方案整理彙總

最近用MySQL做統計的需求比較多,這裏整理一些常用的場景方便後期查閱,同時也是拋磚引玉的過程。其中包括普通的分組統計,連續的每日統計,區間範圍統計。

普通分組統計

場景一:根據訂單狀態統計訂單數量。
一個很常見,也很簡單的統計需求。其中狀態字段是訂單實體的一個屬性。

@Query("SELECT status, COUNT(id) FROM Order GROUP BY status")
fun summaryOrderByStatus(): Array<Array<String>>?

場景二:根據訂單中商品類目統計訂單數量和金額。
比場景一稍微麻煩了一點,商品字段是訂單實體的一個屬性,而類目字段纔是商品實體的一個屬性。參考代碼:(Kotlin語法)

@Query("SELECT commodity.category, COUNT(id), SUM(finalPrice) FROM Order GROUP BY commodity.category")
fun summaryOrderByCommodityCategory(): Array<Array<String>>?

小結:

  1. 分組統計少不了GROUP BY語句,如果需要加查詢條件,請在其前面添加 WHERE 語句。
  2. 統計數量用COUNT,統計總和用SUM函數,有GROUP BY的地方,少不了這些聚合函數。
  3. 統計返回的結果是字符串類型的二維數組。
  4. 以內嵌屬性分組,如果是SpringDataJpa框架,則可以直接通過”實體類.屬性名”的方式。

每日統計

在做每日,每週,每月統計時,遇到返回日期不是連續的情況。
原因是數據庫中沒有值,而我們理想狀態應該是:如果沒有值則默認爲零,使其數據是連續的日期。

場景三:統計結果日期可能不連續
如果數據庫中某個時間段沒有值,那統計出來的結果會缺這段時間。參考代碼:(sql語句)

-- 統計每日
SELECT DATE_FORMAT(create_date,'%Y-%m-%d') as days, COUNT(id) count FROM order GROUP BY days;
-- 統計每週
SELECT DATE_FORMAT(create_date,'%Y-%u') as weeks, COUNT(id) count FROM order GROUP BY weeks;
-- 統計每月
SELECT DATE_FORMAT(create_date,'%Y-%m') as months, COUNT(id) count FROM order GROUP BY months;

場景四:統計結果日期連續
要讓日期連續,又要代碼優雅。說實話,困擾了我很久,一直沒有找到很好的解決方法,雖然目前這個方法很挫。但可以解決問題。畢竟抓到老鼠的都是好貓。如果各位有好的建議,望賜教!

解決思路:

  1. 第一步:創建一張date_summary輔助表,字段只需要有date和count(默認值爲零)。
  2. 第二步:先向date_summary表插入10年內的數據。
  3. 第三步:通過UNION ALL 聯合查詢,將空缺的日期補上。
  4. 第二步參考代碼(Kotlin語法)

第二步參考代碼(Kotlin語法)

val startDate = Calendar.getInstance()
startDate.set(2018, 6, 1)
val startTIme = startDate.timeInMillis
val endDate = Calendar.getInstance()
endDate.set(2028, 11, 30)
val endTime = endDate.timeInMillis
val oneDay = 1000 * 60 * 60 * 24L
var time = startTIme
val dates: MutableList<DateSummary> = arrayListOf()
while (time<=endTime) {
   val dateSummary = DateSummary()
   dateSummary.date = SimpleDateFormat("yyyy-MM-dd").format(Date(time))
   dateSummary.count = 0
   dates.add(dateSummary)
   time += oneDay
}
dateSummaryRepository.saveAll(dates)

第三步統計每日的SQL語句

 
SELECT
   summary.oneDay,
   summary.count 
FROM
   (
   SELECT
       DATE_FORMAT( created_date, '%Y-%m-%d' ) oneDay,
       COUNT(id) count 
   FROM
       service_order 
   WHERE created_date BETWEEN "2018-06-01" and "2018-08-01"
   GROUP BY oneDay 
   UNION ALL
       (
       SELECT
           DATE_FORMAT( date, '%Y-%m-%d' ) templateDay,
           count
       FROM
           date_summary
       WHERE date BETWEEN "2018-06-01" and "2018-08-01"
       GROUP BY
           templateDay
       ) 
   ) summary 
GROUP BY
   summary.oneDay 
ORDER BY
   summary.oneDay ASC

小結:

  1. MySQL的DATE_FORMAT(date,format) 函數用於以不同的格式顯示日期/時間數據,文章後面會詳細介紹
  2. MySQL的UNION 操作符用於合併兩個或多個SELECT語句的結果集,文章後面會詳細介紹

區間範圍統計

這是一個較爲常見的需求,比如按照年齡段統計人員分佈情況,甚至要求分別統計男女人數分佈情況。

場景五:根據小區年齡段統計人數
只根據年齡範圍統計,沒有其他限制條件,使用SUM只需要加一。

SELECT INTERVAL(age,10,20,30,40,50,60,70,80,90) AS ageRatio, 
SUM(1) AS count FROM user GROUP BY ageRatio

場景六:根據小區年齡段統計男女人數
在場景五的基礎上多了一個區分性別,用流程控制函數來設置SUM加一的情況。

SELECT INTERVAL(age,10,20,30,40,50,60,70,80,90) AS ageRatio, 
SUM(CASE WHEN sex=1 THEN 1 ELSE 0 END) AS male,
SUM(CASE WHEN sex=0 THEN 1 ELSE 0 END) AS female FROM user GROUP BY ageRatio

小結:

  1. 通過區間統計需要使用MySQL的INTERVAL函數,第一個參數是需要比較的字段,後面是比較的區間,值必須從小到大
  2. 區間統計的結果也是二維數組,注意返回的結果可能不是連續的(這裏的不連續可以用代碼解決,畢竟區間數量較少)。第一個參數返回的是區間的下標,從0開始。
  3. 當age的值在區間範圍內就SUM加一,也可以通過流程控制函數(CASE WHEN THEN ELSE END)來判斷是加一還是加零

MySQL知識點

知道現在都是快餐文化,大家都很忙,很少有時間去揣摩各語法的特點。所以先把常用的場景寫在前面,語法知識寫在後面。

  • GROUP BY 分組
  1. 分組一般與聚合函數一起使用如SUM,COUNT等
  2. GROUP BY 在WHERE 語句之後
  • DATE_FORMAT 時間格式化
  1. 用來修改時間的格式
  2. 語法格式: DATE_FORMAT(date,format) date必須是合格的時間參數,format是輸出時間格式
  3. 常見的format格式有:
  • %Y: 4位數的年,
  • %y: 2位數的年,
  • %m: 2位數的月(00~12),
  • %M: 英文單詞的月,
  • %d: 2位數的日(00~31),
  • %u: 周,星期一是一週的第一條,
  • 更多可以訪問w3school
  • UNION 聯合結果
  1. UNION可以合併、聯合,將多次查詢結果合併成一個結果,通過查詢結果合併解決了統計不連續的情況。
  2. 多條查詢語句的列數必須一致,各列的順序最好一致。場景四中,兩條sql都只查詢了date和count,且順序保持一致。
  3. union 去重,union all包含重複項
  • INTERVAL 比較間距
  1. INTERVAL()函數是比較列表(N, arg1, arg2, arg3…argN)中的N值。
  2. INTERVAL()函數如果N<arg1則返回0,如果N<arg2則返回1,如果N<arg3則返回2,如果N爲NULL,它將返回-1。
  3. 列表值必須是arg1 < arg2 < arg3 的形式才能正常工作。
  • 流程控制函數
  1. case when then else end 是流程控制函數中的一種,還有一種是if函數
  2. 使用語法:
 
case 
when 條件1 then 值1
when 條件2 then 值2
...
else 值n
end

 

 

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