天天看點

coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

GROUP BY 語句根據一個或多個字段對結果集進行分組(也就是把值相同放到一個組中,顯示組中一條記錄),實作對每個組而不是對整個結果集統計。SELECT子句中的列名必須為分組列、聚合函數或常量。

文法形式為:

SELECT [field1, field12, ..., ] fun_name

FROM tablename

JOIN  ON join_condition

WHERE where_conditon

GROUP BY field1, field12, ..., fieldn

[WITH ROLLUP]

[HAVING having_condition]

[ORDER BY field1, field12, ..., fieldn [ASC | DESC]]

參數說明:

SELECT 子句中的列必須為分組列(寫在GROUP  BY 後面的列)、聚合函數(SUM、MAX、AVG等)或常量(MySql5.7以後版本,預設是開啟了only_full_group_by 模式的)。

fun_name 表示聚合函數,常見的有:SUM(總和)、AVG(平均值)、COUNT(行數)、MAX(最大值)、MIN(最小值)、GROUP_CONCAT(串聯的字元串)、JSON_ARRAYAGG(将結果集作為單個JSON數組傳回)、JSON_OBJECTAGG(将結果集作為單個JSON對象傳回)。

GROUP BY 表示一個或多個字段對結果集進行分組,比如按照部門統計人數。

WITH ROLLUP 是可選的,表示是否對分組後的結果再進行統計。

HAVING  表示對分組的結果再進行條件過濾,比如統計部門人數大于10人的部門。(HAVING和WHERE的差別,HAVING 是對分組後的結果進行條件的過濾,而WHERE是在分組前進行條件的過濾,如果可以,我們應盡可能用WHERE先過濾記錄,這樣結果集減少,提高分組效率。)

GROUP BY用法舉例

我們以MySql示例employees庫示範,employees庫表描述可以參考:mysql示例employees資料庫安裝和介紹

統計公司的總人數

SELECT COUNT(1) FROM employees ;
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

注意:使用count(列名)當某列出現null值的時候,count(*)仍然會計算,但是count(列名)不會。

統計各個部門人數

SELECT `dept_no`,COUNT(1) FROM `dept_emp` GROUP BY `dept_no`;
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

通過統計公司總人數和統計各個部門人數,我們能看到GROUP BY 作用,實作對每個組而不是對整個結果集統計。

在對結果集資料分組以後,SELECT 子句中的列必須為分組列、聚合函數(SUM、MAX、AVG等)或常量。如果我們在統計部門人數增加沒有出現在GROUP BY後面列emp_no(員工id),會怎樣?

coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

報錯了:列emp_no不在GROUP BY子句中,并且也不是聚合函數,這與sql_mode=only_full_group_by 不相容(在MySql5.7以後版本,預設開啟了only_full_group_by 模式的,以前的版本沒有開啟only_full_group_by 模式,不會報錯)。

為什麼分組後不能再引用原表中的列(不在 GROUP BY 子句的列)?

GROUP BY的作用是将表中結果集分組, GROUP BY 操作的對象是由多個員工組成的小組,小組的屬性隻能是SUM、AVG、MAX等統計的屬性,而emp_no(員工id)是每個員工屬性,并不是小組的屬性。

假如分組後分組的某個非分組的列值都一樣,或者說隻想随機選擇一個列值,那該怎麼操作?有兩種方法:

1、使用ANY_VALUE()函數

SELECT ANY_VALUE(`emp_no`) `emp_no`, `dept_no`,COUNT(1) FROM `dept_emp` GROUP BY `dept_no`;
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

注意,如果是在MySql5.7版本以下使用ANY_VALUE()函數會報錯(代碼示範的MySql5.5版本)。

coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

2、關閉only_full_group_by 模式

通過select @@sql_mode查出sql_mode,去掉ONLY_FULL_GROUP_BY後複制過來

SELECT @@sql_mode;
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

修改my.cnf檔案,在mysqld下面增加

sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

然後重新開機MySql服務

建議不要在SELECT子句中引用不在GROUP BY子句中列,它會傳回一個不确定的值,這可能不是您想要的。

GROUP_CONCAT()函數使用

作用将group by産生的同一個分組中的值連接配接起來,傳回一個字元串結果。

文法group_concat( [distinct] 要連接配接的字段 [order by 排序字段 asc/desc  ] [separator '分隔符'] )。

統計每個部門曆任經理,并按照當經理時間從前到後排序

SELECT GROUP_CONCAT(`emp_no` ORDER BY `from_date` ASC SEPARATOR ',') `emp_no`, `dept_no` FROM `dept_manager` GROUP BY `dept_no`;
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

說明:

group_concat長度:group_concat預設最大長度是1024,超過截取前1024長度字元。

查詢group_concat:show variables like 'group_concat_max_len';

修改group_concat:修改配置檔案my.conf(需要重新開機mysql服務) group_concat_max_len = 2048;

WITH ROLLUP子句實作在分組統計資料基礎上再進行相同的統計

既統計部門人數,也統計所有部門總人數

SELECT `dept_no`, COUNT(1) FROM `dept_emp` GROUP BY `dept_no` WITH ROLLUP;
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

WITH ROLLUP子句可以實作在分組統計資料基礎上再進行相同的統計,像上面的例子,統計所有部門總人數,NULL 331603,如何把字段WITH ROLLUP彙總字段NULL改成total,方法有很多,比如使用IFNULL(expr1,expr2)、IF(expr1,expr2,expr3)、GROUPING(expr [, expr] ...)、COALESCE(expr1,expr2,expr3,....,exprn)函數。

下面例子我們使用COALESCE()函數

COALESCE(a, b, c, ...., n) 作用是将傳回傳入的參數中第一個非null的值。

SELECT COALESCE(`dept_no`,'total') `dept_no`, COUNT(1) FROM `dept_emp` GROUP BY `dept_no` WITH ROLLUP;
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

使用ROLLUP時的其他注意事項

在MySQL 8.0.12之前,使用時ROLLUP,不能同時使用ORDER BY子句對結果進行排序。

SELECT COALESCE(`dept_no`,'total') `dept_no`, COUNT(1) FROM `dept_emp` GROUP BY `dept_no` WITH ROLLUP ORDER BY COUNT(1) DESC;
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

但是你可以采用子查詢的辦法實作排序

 SELECT * FROM (SELECT COALESCE(`dept_no`,'total') `dept_no`,  COUNT(1) `cnt` FROM `dept_emp`  GROUP BY `dept_no` WITH ROLLUP)  AS `sub` ORDER BY `cnt` DESC;
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

從MySQL 8.0.12開始,ORDER BY并且 ROLLUP可以一起使用

SELECT COALESCE(`dept_no`,'total') `dept_no`, COUNT(1) FROM `dept_emp` GROUP BY `dept_no` WITH ROLLUP ORDER BY COUNT(1) DESC;
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

要注意:與SELECT子句列一樣,ORDER BY子句的列也必須為分組列、聚合函數(SUM、MAX、AVG等)。

HAVING 子句對分組結果進行篩選

統計2000年以後進入部門且數量大于500人的部門

SELECT `dept_no`, COUNT(1) `cnt`  FROM `dept_emp` WHERE Year(`from_date`) > 2000 GROUP BY `dept_no` HAVING `cnt` > 500;
           
coalesce函數用法 sql_MySql中GROUP BY分組查詢用法詳解

WHERE和HAVING差別

WHERE在查詢傳回之前對資料庫中的查詢條件進行過濾,即在結果傳回之前起作用,且where後面不能使用聚合函數,WHERE不可以用字段别名(where後面不能使用聚合函數是因為where的執行順序在聚合函數之前)。

HAVING 在查詢資料庫的結果分組之後進行過濾,即在結果傳回之後起作用,是以HAVING 後面可以使用聚合函數,HAVING子句可以使用字段别名。

繼續閱讀