最近在給喜樂喜樂網的後臺添加一系列的統計功能,遇到不少須要按條件計數的狀況。嘗試了幾種方法,下面簡要記錄,供你們參考。 問題描述 爲使討論簡單易懂,我將問題稍做簡化,去掉諸多的背景。 從前有一個皇帝,他有50個妃子,這些妃子很沒有天理的給他生了100,000個兒子,因而,皇帝很苦惱,海量的兒子很難管理,並且,他想知道每一個妃子給他生了多少個兒子,從而論功行賞,這很難辦。因而,皇帝請了一個程序員幫他編了一個程序,用數據庫來存儲全部的兒子的信息,這樣就能夠用程序來統計和管理啦。 數據庫的結構以下: id 皇子的惟一編號 mother 皇子母親的惟一編號 皇帝把妃子分紅了兩個等級,天宮娘娘(編號小於25)和地宮娘娘(編號大於等於25),他想知道天宮娘娘們和地宮娘娘們的生育能力孰強孰弱。因而,程序員開始寫SQL Query了。 方法1:使用GROUP BY SQL Query SELECT COUNT(*) FROM `prince` GROUP BY `mother` > 24; 執行結果 count(*) 50029 49971 在100,000行數據上的運行時間:0.0335 秒 分析 這種GROUP BY方法的最大問題在於:沒法區分所獲得的結果。這兩個數字哪個是天宮娘娘們所生的皇子數,哪個是地宮娘娘們所生的皇子數呢?不知道。因此,儘管它統計出了總數,可是沒有什麼意義。 所以,爲了區分統計結果,必需要把條件 mother > 24 也做爲一個字段在結果集中做爲一個字段體現出來,修改後的sql以下: SELECT COUNT(*) AS `number`, `mother` > 24 AS `type` FROM `prince` GROUP BY `mother` > 24; 執行結果 number type 50029 0 49971 1 條件表達式做爲字段時,該字段的值就是該條件表達式的值,所以,對應咱們的例子,type = 1 也就是表示 mother > 24 的值爲1,所以,第二行中的數字表明地宮娘娘們所生的皇子數。 通過修改後,咱們看出,天宮娘娘們略勝一籌。 優缺點 缺點是顯而易見的,因爲使用了條件表達式做爲分組依據,它只能作二元的劃分,對於要分紅多類進行統計的狀況不可以勝任。好比要分別統計1~10號、11~24號,25號~50號妃子的產子數,就沒法實現了。 另外,因爲使用了GROUP BY,所以涉及到排序,執行時間上要更長。 我暫時沒有發現這種方法的優勢。 方法2:使用嵌套的SELECT 使用嵌套的SELECT也能夠達到目的,在每一個SELECT子句中統計一個條件下的數據,而後用一個主SELECT把這些統計數據整合起來。 SQL Query SELECT ( SELECT COUNT( * ) FROM `prince` WHERE `mother` >24 ) AS `digong`, ( SELECT COUNT( * ) FROM `prince` WHERE `mother` <=24 ) AS `tiangong` 執行結果 digong tiangong 49971 50029 在100,000行數據上的運行時間:0.0216 秒 分析 這種嵌套SELECT的方法很是直觀,就是分別統計各個條件下的數值,最後進行彙總,通俗易懂,跟天然語言沒啥區別了。 優缺點 優勢就是直觀,並且速度也比GROUP BY要快。雖然是3條SELECT語句,看起來比GROUP BY的方案多了2條語句,可是它不涉及到排序,這就節省了不少時間。 缺點可能就是語句稍多,對語句數量有潔癖的同窗可能會比較不舒服。 方法3:使用CASE WHEN CASE WHEN語句的功能很強大,能夠定義靈活的查詢條件,很適合進行分類統計。 SQL Query SELECT COUNT( CASE WHEN `mother` >24 THEN 1 ELSE NULL END ) AS `digong`, COUNT( CASE WHEN `mother` <=24 THEN 1 ELSE NULL END ) AS `tiangong` FROM prince 執行結果 digong tiangong 49971 50029 在100,000行數據上的運行時間:0.02365825 秒 分析 此方法的關鍵在於 COUNT( CASE WHEN `mother` >24 THEN 1 ELSE NULL END ) 這裏的COUNT和CASE WHEN聯合使用,作到了分類計數。先使用CASE WHEN,當知足條件時,將字段值設置爲 1, 不知足條件時,將字段值設置爲NULL,接着COUNT函數僅對非NULL字段進行計數,因而,問題解決。 優缺點 優勢嘛,此方法也不涉及到排序,所以運行時間上與方法2至關,SELECT語句減小到了 1 條。 缺點就是語句比較長,對語句長度有潔癖的同窗可能會比較不舒服。 總結 對於肯定分類的按條件計數,能夠儘可能不用GROUP BY,從而避免排序動做,加速Query的執行。 若是須要根據某個字段的值進行分類,而該字段的值是可變的,好比皇帝要統計每個妃子的產子數,而他可能不停的再娶不少妃子,這種狀況下,使用方法2和方法3就不太靈光了,仍是使用一個GROUP BY來得簡單便捷。