【Oracle】Oracle之SQL的聚合函数和分组

前情提要:本篇博客将详细介绍oracle的SQL中的常用聚合函数(SUM AVG MAX MIN COUNT)和分组(GROUP BY)及分组限制(HAVING)的子句、语法、功能和示例详解

oracle版本:19c

一、聚合函数

聚合函数对行进行操作,以使每个组一个结果。

1.1 聚合函数的类型和语法

  • AVG 平均值

  • COUNT 求记录与数据个数

  • MAX 最大值

  • MIN 最小值

  • SUM 求和

  • LISTAGG 行转列函数

  • STDDEV 求标准差

  • VARIANCE 求协方差

  • MEDIAN 求中位数

语法

cpp 复制代码
SELECT     group_function(column), ...
FROM	  table
[WHERE	  condition];

1.2 聚合函数使用示例

AVG, MAX, MIN, SUM使用示例

  • 可以使用AVG和SUM对数字进行运算
cpp 复制代码
-- 计算平均工资,最高工资,最低工资,工资总和
SQL> SELECT AVG(salary),MAX(salary),MIN(salary),SUM(salary) FROM employees;

AVG(SALARY) MAX(SALARY) MIN(SALARY) SUM(SALARY)
----------- ----------- ----------- -----------
 6461.83178       24000        2100      691416
  • 可以使用MIN和MAX在数字、字符与日期类型数据上
cpp 复制代码
-- 计算最高工资
SQL> SELECT MAX(salary) FROM employees;

MAX(SALARY)
-----------
      24000

-- 计算最低工资
SQL> SELECT MIN(salary) FROM employees;

MIN(SALARY)
-----------
       2100

-- 判断日期
-- 判断日期标准:哪个日期离当前时间越近,就越大
-- 先修改日期格式方便查看
SQL> ALTER SESSION SET nls_date_format='yyyy-mm-dd hh24:mi:ss';

Session altered.

-- 查看最小日期和最大日期
SQL> SELECT MIN(hire_date),MAX(hire_date) FROM employees;

MIN(HIRE_DATE)      MAX(HIRE_DATE)
------------------- -------------------
2001-01-13 00:00:00 2008-04-21 00:00:00

COUNT函数使用示例

  • COUNT(*)或COUNT(1)返回表中的行数
cpp 复制代码
SQL> SELECT COUNT(*) FROM employees;

  COUNT(*)
----------
       107
       
SQL> SELECT COUNT(1) FROM employees;
  COUNT(1)
----------
       107       
  • COUNT(expr)返回expr具有非空值的行数
cpp 复制代码
-- 表中原本有107行数据,但是COUNT(commission_pct)却只统计出35行,是因为commission_pct中有空值,COUNT不会统计空值
SQL> SELECT COUNT(commission_pct) FROM employees;

COUNT(COMMISSION_PCT)
---------------------
                   35
                 
-- 如果想统计所有的行,但是又存在空值,则可以使用NVL将空值进行转换
SQL> SELECT COUNT(NVL(commission_pct,0)) FROM employees;

COUNT(NVL(COMMISSION_PCT,0))
----------------------------
                         107

使用DISTINCT关键字

  • COUNT(DISTINCT expr)返回表达式中的不同非null值的数量。

  • 在EMPLOYEES表中显示不同部门值的数量:

cpp 复制代码
-- 如果不想统计重复值可以使用DISTINCT去重
SQL> SELECT COUNT(department_id),COUNT(DISTINCT DEPARTMENT_ID) FROM EMPLOYEES;

COUNT(DEPARTMENT_ID) COUNT(DISTINCTDEPARTMENT_ID)
-------------------- ----------------------------
                 106                           11
-- 不去重统计department_id有106行,去重后只有11行了

聚合函数和NULL值

  • 忽略列中的NULL值
cpp 复制代码
-- 使用AVG计算commission_pct,但是由于commission_pct存在空值会被忽略,导致结果不准确
SQL> SELECT AVG(commission_pct) FROM employees;
AVG(COMMISSION_PCT)
-------------------
         .222857143
  • 使用NVL函数强制将列中的NULL值进行转换
cpp 复制代码
SQL> SELECT AVG(NVL(commission_pct,0)) FROM employees;

AVG(NVL(COMMISSION_PCT,0))
--------------------------
               .0728971963

二、分组

对数据进行分组

按多列分组

GROUP BY子句语法

cpp 复制代码
SELECT    column, group_function(column)
FROM      table
[WHERE    condition]
[GROUP BY group_by_expression]
[ORDER BY column];

2.1 GROUP BY 子句

SELECT列表中所有不在分组(聚合)函数中的列必须在GROUP BY子句中

GROUP BY列不必在SELECT列表中

示例

  • 按照DEPARTMENT_ID【部门编号】进行分组,分组以后求每个部门的平均工资
cpp 复制代码
SQL> SELECT department_id, AVG(salary) FROM employees GROUP BY department_id;	-- 先分组再聚合

DEPARTMENT_ID AVG(SALARY)
------------- -----------
           50  3475.55556
           40        6500
          110       10154
           90  19333.3333
           30        4150
           70       10000
                     7000
           10        4400
           20        9500
           60        5760
          100  8601.33333

DEPARTMENT_ID AVG(SALARY)
------------- -----------
           80  8955.88235

12 rows selected.
  • 按照部门分组后再按照岗位分组,最后求不同部门的不同岗位的平均工资并且按照部门升序排序
cpp 复制代码
SQL> SELECT department_id,job_id,SUM(salary)
  2  FROM employees
  3  WHERE department_id>40
  4  GROUP BY department_id,job_id
  5  ORDER BY department_id;

DEPARTMENT_ID JOB_ID     SUM(SALARY)
------------- ---------- -----------
           50 SH_CLERK         64300
           50 ST_CLERK         55700
           50 ST_MAN           36400
           60 IT_PROG          28800
           70 PR_REP           10000
           80 SA_MAN           61000
           80 SA_REP          243500
           90 AD_PRES          24000
           90 AD_VP            34000
          100 FI_ACCOUNT       39600
          100 FI_MGR           12008

DEPARTMENT_ID JOB_ID     SUM(SALARY)
------------- ---------- -----------
          110 AC_ACCOUNT        8300
          110 AC_MGR           12008

13 rows selected.
  • 求部门的平均工资
cpp 复制代码
-- GROUP BY 列不必在SELECT列表中
SQL> SELECT AVG(salary)
  2  FROM employees
  3  GROUP BY department_id;

AVG(SALARY)
-----------
 3475.55556
       6500
      10154
 19333.3333
       4150
      10000
       7000
       4400
       9500
       5760
 8601.33333

AVG(SALARY)
-----------
 8955.88235

12 rows selected.

-- 但是SELECT列中不在聚合函数中的列必须在GROUP BY列中
SQL> SELECT department_id,AVG(salary)
  2  FROM employees
  3* GROUP BY department_id;
DEPARTMENT_ID AVG(SALARY)
------------- -----------
           50  3475.55556
           40        6500
          110       10154
           90  19333.3333
           30        4150
           70       10000
                     7000
           10        4400
           20        9500
           60        5760
          100  8601.33333

DEPARTMENT_ID AVG(SALARY)
------------- -----------
           80  8955.88235

12 rows selected.

2.2 使用聚合函数的非法查询

SELECT列表中不是聚合函数的任何列或表达式都必须在GROUP BY子句中:

错误示例

cpp 复制代码
SQL> SELECT department_id,COUNT(last_name)
  2  FROM employees;
SELECT department_id,COUNT(last_name)
       *
ERROR at line 1:
ORA-00937: not a single-group group function
-- 必须添加GROUP BY子句以计算每个department_id的last_name。

SQL> SELECT department_id,job_id,COUNT(last_name)
  2  FROM employees
  3  GROUP BY deepartment_id;
GROUP BY deepartment_id
         *
ERROR at line 3:
ORA-00904: "DEEPARTMENT_ID": invalid identifier
-- 在GROUP BY中添加job_id或从SELECT列表中删除job_id列。
  • 您不能使用WHERE子句来限制组。

  • 您可以使用HAVING子句来限制组。

  • 您不能在WHERE子句中使用聚合函数。

错误示例

cpp 复制代码
SQL> SELECT department_id,AVG(salary)
  2  FROM employees
  3  WHERE AVG(salary) > 8000
  4  GROUP BY department_id;
WHERE AVG(salary) > 8000
      *
ERROR at line 3:
ORA-00934: group function is not allowed here
-- 不能使用WHERE子句来限制分组

2.3 使用HAVING子句限制分组结果集

当您使用HAVING子句时,Oracle服务器对组的限制如下:

1.行被分组。

2.应用分组功能。

3.显示与HAVING子句匹配的组。

使用HAVING的限制

  • 不能引用非分组列:HAVING条件中不能使用未在GROUP BY中指定的列

  • 不能使用别名:不能直接使用SELECT子句中定义的别名,必须使用原始列名或聚合函数

  • 不能包含子查询:HAVING条件中不能嵌套子查询

语法

cpp 复制代码
SELECT    column, group_function
FROM      table
[WHERE    condition]
[GROUP BY group_by_expression]
[HAVING   group_condition]
[ORDER BY column];

使用HAVING子句示例

  • 查看平均工资大于8000的部门
cpp 复制代码
SQL> SELECT department_id,AVG(salary)
  2  FROM employees
  3  GROUP BY department_id
  4  HAVING AVG(salary)>8000;

DEPARTMENT_ID AVG(SALARY)
------------- -----------
          110       10154
           90  19333.3333
           70       10000
           20        9500
          100  8601.33333
           80  8955.88235

6 rows selected.
  • 查询工资总和大于13000且不含'REP'字符的岗位,并且按照工资总和升序排序
cpp 复制代码
SQL> SELECT job_id,SUM(salary) PAYROLL
  2  FROM employees
  3  WHERE job_id NOT LIKE '%REP%'
  4  GROUP BY job_id
  5  HAVING SUM(salary)>13000
  6  ORDER BY SUM(salary);

JOB_ID        PAYROLL
---------- ----------
PU_CLERK        13900
AD_PRES         24000
IT_PROG         28800
AD_VP           34000
ST_MAN          36400
FI_ACCOUNT      39600
ST_CLERK        55700
SA_MAN          61000
SH_CLERK        64300

9 rows selected.

三、嵌套聚合函数

聚合函数可以嵌套使用

示例

  • 显示最高平均工资
cpp 复制代码
SQL> SELECT MAX(AVG(salary))
  2  FROM employees
  3  GROUP BY department_id;

MAX(AVG(SALARY))
----------------
      19333.3333
相关推荐
jamon_tan20 小时前
linux下lvgl8.3动态库编译
linux
m0_7489203620 小时前
Golang goquery怎么解析HTML_Golang goquery教程【核心】
jvm·数据库·python
m0_7467523020 小时前
golang如何编写Markdown转HTML工具_golang Markdown转HTML工具编写详解
jvm·数据库·python
weixin_4249993620 小时前
C#怎么使用TopLevel顶级语句 C#顶级语句怎么写如何省略Main方法简化控制台程序【语法】
jvm·数据库·python
Elastic 中国社区官方博客20 小时前
Elastic Security、Observability 和 Search 现在在你的 AI 工具中提供交互式 UI
大数据·运维·人工智能·elasticsearch·搜索引擎·安全威胁分析·可用性测试
qq_3721542321 小时前
如何利用Bootstrap的Flex工具类快速排版
jvm·数据库·python
qq_6543669821 小时前
golang如何实现菜单权限动态加载_golang菜单权限动态加载实现详解
jvm·数据库·python
arronKler21 小时前
大数据量高并发的数据库优化
服务器·数据库·oracle
星辰_mya21 小时前
OSI 七层模型之“跨国诈骗集团”深度讲解
运维·服务器·后端·面试·架构师
贝锐21 小时前
如何破解商用安卓无人值守运维痛点,向日葵赋能数字化高效转型
运维