1. 程式人生 > >【SQL】分組資料,過濾分組-group by , having

【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子句之前;

示例:

<span style="font-family:SimSun;font-size:10px;">select departmentid, count(*) as 'number' from basicdepartment group by departmentid;</span>
departmentid將資料集進行了分組,然後再進行各個組的統計資料分別有多少。

如果不用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 查詢。