sql分组查询group by结合count,sum统计语句的实现(附带sql详细分析步骤)
日常寫代碼經(jīng)常會遇到數(shù)據(jù)統(tǒng)計的業(yè)務(wù)場景,分組查詢 group by 結(jié)合 count 和 sum 的復(fù)雜語句寫起來容易令人頭大,在這里分享兩個比較復(fù)雜的統(tǒng)計場景,提供詳細(xì)分析思路和最終sql語句,希望能給大家?guī)韼椭?/p>
場景1:統(tǒng)計每個學(xué)生的加減分次數(shù)和總分
庫表結(jié)構(gòu)如下所示:
學(xué)生分?jǐn)?shù)表:student_score
| id | 自增編號 | bigint | |
| student_name | 學(xué)生姓名 | varchar | |
| score | 分?jǐn)?shù) | double | |
| sort | 分?jǐn)?shù)類型 | int | 1-加分;2-減分; |
| is_delete | 刪除標(biāo)志位 | int | 默認(rèn)為0; |
一上來不著急寫 sql,先來分析一下:
因為統(tǒng)計的是每個學(xué)生的分?jǐn)?shù),所以根據(jù)學(xué)生名稱 student_name 進(jìn)行 group by 分組查詢。
需要獲取的字段包括 學(xué)生名稱 student_name,加分次數(shù) add_count,扣分次數(shù) sub_count,總加分 add_score,總扣分 sub_score,其中,學(xué)生名稱不需要計算,因此只需處理次數(shù)和分?jǐn)?shù)。
我們知道,count() 主要用于求行的個數(shù)累計,所以當(dāng)分?jǐn)?shù)類型 sort 為 1,則增加加分次數(shù),sort 為 2,則增加扣分次數(shù);而 sum() 用于求和累加,因而使用 sum() 來計算總分,分?jǐn)?shù)類型 sort 為 1,則加分,sort 為 2,則減分。
有了清晰的思路,sql就不難寫了:
SELECTstudent_name,count(sort = 1 OR NULL) add_count,count(sort = 2 OR NULL) sub_count,sum(IF(sort = 1, score, 0)) add_score,sum(IF(sort = 2, score, 0)) sub_score FROMstudent_score WHEREis_delete = 0 GROUP BYstudent_name原始表數(shù)據(jù):
統(tǒng)計結(jié)果:
這里的次數(shù)和分?jǐn)?shù)的條件判斷是通過 if 語句來實現(xiàn)的,我們也可以通過 case when 語句來實現(xiàn):
場景2:按照權(quán)重統(tǒng)計每個學(xué)生的體測成績
體育測試中我們要根據(jù)不同的指標(biāo)對學(xué)生進(jìn)行打分,目前分為5項指標(biāo):800米,50米,立定跳遠(yuǎn),仰臥起坐和坐位體前屈。總分為100分,每項的分?jǐn)?shù)權(quán)重占比不一樣,如下表所示:
| 800米 | 30 |
| 50米 | 15 |
| 立定跳遠(yuǎn) | 20 |
| 仰臥起坐 | 15 |
| 坐位體前屈 | 20 |
其中立定跳遠(yuǎn)需要測試3次,每次都進(jìn)行打分,需要根據(jù)這3次的得分計算出平均分作為最終得分,未來其他指標(biāo)也可能采用這種方式進(jìn)行打分。
需求明確了,先來設(shè)計數(shù)據(jù)庫表,由于每項指標(biāo)的權(quán)重是固定的,可以采用單獨一個表來存儲指標(biāo)權(quán)重:
指標(biāo)權(quán)重表:index_score
| id | 自增編號 | bigint | |
| index_code | 指標(biāo)編號 | varchar | |
| index_name | 指標(biāo)名稱 | varchar | |
| share | 指標(biāo)權(quán)重 | int | |
| is_delete | 刪除標(biāo)志位 | int | 默認(rèn)為0; |
由于庫表中需要保存全量詳細(xì)的體測記錄,所以需要記錄每個學(xué)生的指標(biāo)和對應(yīng)的評分。這里通過指標(biāo)編號進(jìn)行關(guān)聯(lián),結(jié)果記錄表如下所示:
結(jié)果記錄表:score_record
| id | 自增編號 | bigint | |
| student_name | 學(xué)生名稱 | varchar | |
| index_code | 指標(biāo)編號 | varchar | |
| score | 對應(yīng)指標(biāo)得分 | double | |
| is_delete | 刪除標(biāo)志位 | int | 默認(rèn)為0; |
我們需要通過一個sql關(guān)聯(lián) 指標(biāo)權(quán)重表 和 結(jié)果記錄表 來獲取每個學(xué)生的姓名和總得分。這個場景比較復(fù)雜,一步一步來分析:
首先先來處理最復(fù)雜的立定跳遠(yuǎn)項,先計算每個學(xué)生的3次得分的平均分,由于未來其他指標(biāo)也可能采用這種方式進(jìn)行打分,那么我們就要根據(jù)學(xué)生姓名和指標(biāo)編號共同進(jìn)行 group by 分組后再獲取平均值:
SELECTstudent_name,index_code,round(avg(score), 1) index_avg FROMscore_record r WHEREr.is_delete = 0 GROUP BYstudent_name, index_code原始表數(shù)據(jù):
統(tǒng)計結(jié)果:
統(tǒng)計出每個學(xué)生的各項指標(biāo)得分就完成了第一步,第二步需要根據(jù)各項指標(biāo)的權(quán)重結(jié)合得分計算總分。這就需要結(jié)合指標(biāo)權(quán)重表來獲取每項指標(biāo)的權(quán)重占比 share,再乘以第一步計算出的平均值 index_avg 后,最后使用 sum() 來計算出總分。
當(dāng)然這里需要根據(jù)學(xué)生姓名來進(jìn)行分組,對于計算出的總分還要使用 round() 函數(shù)保留兩位小數(shù),最終 sql 如下:
SELECTround(sum(s.share * t.index_avg) / 100, 2) score, t.student_name FROM(SELECTstudent_name,index_code,round(avg(score), 1) index_avgFROMscore_record rWHEREr.is_delete = 0GROUP BYstudent_name,index_code) t LEFT JOIN index_score s ON t.index_code = s.index_code GROUP BYt.student_name統(tǒng)計結(jié)果:
這樣一個看起來有點復(fù)雜的 sql,采用從里到外逐步分析的方式,也就可以輕松寫出來了。
總結(jié)
以上是生活随笔為你收集整理的sql分组查询group by结合count,sum统计语句的实现(附带sql详细分析步骤)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 乘法逆元3种方法总结[最全]
- 下一篇: 苹果录屏精灵_安卓不仿苹果静音键?千万别