【SQL】分組資料,過濾分組-group by , having
建立分組 - GROUP BY
分組是在SELECT語句的GROUP BY子句中建立的。它的作用是通過一定的規則將一個數據集劃分成若干個小的區域,然後針對若干個小區域進行資料處理。SELECT子句中的列名必須為分組列或列函式,列函式對於GROUP BY子句定義的每個組各返回一個結果。
一些規定:
- GROUP BY 子句可以包含任意數目的列,這使得能對分組進行巢狀,為資料分組提供更細緻的控制;
- 如果在GROUP BY子句中嵌套了分組,資料將在最後規定的分組上進行彙總;
- GROUP BY子句中列出的每個列都必須是檢索列或有效的表示式。如果在SELECT中使用表示式,則必須在GROUP BU子句中指定相同的表示式,不能使用別名;
- 大多數SQL實現不允許GROUP BU列帶有長度可變的資料型別(如文字或備select departmentid, departmentname from basicdepartment group by departmentid;注型欄位);
- 除聚集計算語句外,SELECT語句中的每個列都必須在GROUP BY子句中給出;
- 如果分組列中具有NULL值,則NULL將作為一個分組返回。如果列中有多行NULL值,它們將分為一組;
- GROUP BY子句必須出現在WHERE子句之後,ORDER BY子句之前;
示例:
departmentid將資料集進行了分組,然後再進行各個組的統計資料分別有多少。<span style="font-family:SimSun;font-size:10px;">select departmentid, count(*) as 'number' from basicdepartment group by departmentid;</span>
如果不用count(*)而用類似下面的語法:
<span style="font-family:SimSun;font-size:10px;">select departmentid, departmentname from basicdepartment group by departmentid;</span>
將會出現錯誤,選擇列表中的departmentname無效,因為該列沒有包含在聚合函式或者GROUP BY子句中。
注意:如果在返回集欄位中,這些欄位要麼就要包含在GROUP BY語句的後面,作為分組的依據;要麼就要被包含在聚合函式中
過濾分組 - HAVING
除了能用GROUP BY分組資料外,SQL還允許過濾分組,規定包括哪些分組,排除哪些分組。例如,可能想要列出至少有兩個訂單的所有顧客,為了得出這種資料,必須基於完整的分組而不是個別的行進行過濾。
WHERE過濾行,而HAVING過濾分組。HAVING支援所有WHERE操作符,HAVING子句中能使用聚集函式。WHERE在資料分組前進行過濾。HAVING在資料分組後進行過濾。WHERE排除的行不包括在分組中。
示例:
select cust_id, count(*) as orders from Orders group by cust_id having count(*) >= 2;
分組 V.S. 排序 - GROUP BY V.S. ORDER BY
ORDER BY | GROUP BY |
排序產生的輸出 | 分組行,但輸出可能不是分組的順序 |
任意列都可以使用 | 只可能使用選擇列或表示式列,而且必須使用每個選擇列表達式 |
不一定需要 | 如果與聚集函式一起使用列,則必須使用 |
千萬不要僅依賴GROUP BY排序資料。
示例
下表:學生號(SNO),課程名(PNO),成績(GRADE)
1YY
90
1SX98
1YW95
2YY92
2SX91
2YW89
3YY96
3SX88
3YW85
4YY88
4SX89
4YW95
1. 顯式90分以上學生的課程名和成績
select * from sc where GRADE >= 90
4YW
95
3YY96
2YY92
2SX91
1YY90
1SX98
1YW95
2. 顯式每個學生的成績在90分以上的各有多少門
select SNO, count(*) from sc where GRADE >= 90 group by SNO
13
22
31
41
3. 至少有兩門課程在90分以上的學生號及90分以上的課程數 (過濾分組)
select SNO, count(*) from sc where GRADE >= 90 group by SNO having count(*) >= 2
13
22
4. 選出平均成績大於90分,且語文必須在95以上的學生
select SNO, avg(GRADE) from sc where SNO in (select SNO from sc where PNO = 'YW' and GRADE >= 95) group by SNO having avg(GRADE) >= 90
194.333336
490.666664
***應用***
股票order表 t_order_fidessa_his :
order_id order_qty symbol ex_destination
00001768627ORHK16000933HK
00001768632ORHK11200933HK
00001768634ORHK12000941HK
00001768634ORHK16000941HK
00001768634ORHK16000941HK
00001768634ORHK17000941HK
查詢,同一symbol 是否存在不同的ex_destination值:
select temp.symbol, count(*) from
(select t.symbol as symbol, t.ex_destination as ex_destination from t_order_fidessa_his t group by t.symbol, t.ex_destination) temp
group by temp.symbol having count(*) > 1
通過兩次group by 查詢。