oracle(三)聚合函数、分组、子查询、分页

聚合函数

概念

聚合函数,一般会操作多组数据,并对每一组中的某个列,执行计算并返回单一的值。

聚合函数经常与SELECT语句的GROUP BY子句一同使用,所以也把其它称之为分组函数。

select last_name,dept_id
from s_emp
order by dept_id;

LAST_NAME          DEPT_ID
--------------- ----------
Quick-To-See            10
Magee                   31
Nagayama                31
Giljum                  32
Sedeghi                 33
Nguyen                  34
Patel                   34
Dumas                   35
Urguhart                41
Ngao                    41
Smith                   41

可以看出,部门id的员工划分在同一块,可以通过这一特性进行分组

-- 对数据进行分组,按照dept_id相同的员工是一个组,进行划分
select dept_id,count(*),sum(salary)
from s_emp
group by dept_id


   DEPT_ID   COUNT(*) SUM(SALARY)
---------- ---------- -----------
        42          3        3245
        43          3        2700
        34          2        2320
        44          2        2100
        31          2        2800
        32          1        1490
        35          1        1450
        50          2        4050
        41          4        4990
        45          3        3267
        33          1        1515

   DEPT_ID   COUNT(*) SUM(SALARY)
---------- ---------- -----------
        10          1        1450

常用的聚合函数有:

  • avg,求平均值count,计算有多少条数据
  • max,求最大值
  • min,求最小值
  • sum,求和

执行顺序

现在一个select查询语句,由以下几部分组成,并且按照数字的大小进行执行的顺序

select 字段1,字段2 -- 5
from 表 -- 1
where 条件 -- 2
group by 分组条件 -- 3
having 分组筛选条件 -- 4
order by 排序条件 -- 6

聚合函数能够出现的位置:

  1. select后面
  2. having后面
  3. order by后面

注意,where后面一定【不能】出现组函数(聚合函数)

注意,如果select、having语句后面出现了组函数,那么select、having后面没有被组函数修饰的列,就必须出现在group by 后面(非常重要)

默认分组

在使用聚合函数的时候:

  • 如果还使用了group by分组,那么就表示先分组,然后对每一个小组使用聚合函数
  • 如果没有使用group by分组,那么就表示全部数据是一个默认小组,然后对这个全部数据使用聚合函数

例如,查询s_emp表中所有员工的平均工资

select avg(salary)
from s_emp;

AVG(SALARY)
-----------
    1255.08

group by

select dept_id,count(*),min(salary),max(salary),sum(salary),avg(salary)
from s_emp
group by dept_id;

   DEPT_ID   COUNT(*) MIN(SALARY) MAX(SALARY) SUM(SALARY) AVG(SALARY)
---------- ---------- ----------- ----------- ----------- -----------
        42          3         795        1250        3245  1081.66667
        43          3         750        1100        2700         900
        34          2         795        1525        2320        1160
        44          2         800        1300        2100        1050
        31          2        1400        1400        2800        1400
        32          1        1490        1490        1490        1490
        35          1        1450        1450        1450        1450
        50          2        1550        2500        4050        2025
        41          4         940        1450        4990      1247.5
        45          3         860        1307        3267        1089
        33          1        1515        1515        1515        1515

   DEPT_ID   COUNT(*) MIN(SALARY) MAX(SALARY) SUM(SALARY) AVG(SALARY)
---------- ---------- ----------- ----------- ----------- -----------
        10          1        1450        1450        1450        1450

having

查询s_emp表中部门的平均工资大于等于1400的部门

select dept_id,avg(salary)
from s_emp
group by dept_id
having avg(salary)>=1400;

   DEPT_ID AVG(SALARY)
---------- -----------
        31        1400
        32        1490
        35        1450
        50        2025
        33        1515
        10        1450

查询s_emp表中部门的总工资大于等于4000的部门

select dept_id,sum(salary)
from s_emp
group by dept_id
having sum(salary)>=4000;

   DEPT_ID SUM(SALARY)
---------- -----------
        50        4050
        41        4990

子查询

概述

子查询,也称嵌套查询,即一个select语句中嵌套了另外的一个或者多个select语句

子查询的思路就是,把第一个sql语句的查询结果,在第二个sql语句中使用,这时候第一条sql语句的结果,在第二条sql中就可以充当一个where条件中的一个值,或者充当一张虚拟的表。

使用

查询工资比Smith工资高的员工信息

-- 第一步,查询Smith的工资数
select salary
from s_emp
where last_name='Smith';
-- 第二步,查询工资比940高的员工信息
select last_name,salary
from s_emp
where salary>940;
-- 第三步,把第二步中的数字940替换成第一步中的sql语句即可,可以使用小括号包裹子查询
select last_name,salary
from s_emp
where salary>(
    select salary
    from s_emp
    where last_name='Smith'
);

LAST_NAME           SALARY
--------------- ----------
Velasquez             2500
Ngao                  1450
Nagayama              1400
Quick-To-See          1450
Ropeburn              1550
Urguhart              1200
Menchu                1250
Biri                  1100
Catchpole             1300
Havel                 1307
Magee                 1400

查询平均工资比41号部门的平均工资高的部门中员工的信息

-- 第一步,查询41号部门的平均工资
select avg(salary)
from s_emp
where dept_id=41;
-- 第二步,查询平均工资比1247.5高的部门编号
select dept_id
from s_emp
group by dept_id
having avg(salary)>1247.5;
-- 第三步,查询平均工资比1247.5高的部门中员工信息
select last_name,salary,dept_id
from s_emp
where dept_id in(10,31,32,33,35,50);
-- 第四步,把in条件后的数据进行替换
select last_name,salary,dept_id
from s_emp
where dept_id in(
    select dept_id
    from s_emp
    group by dept_id
    having avg(salary)>1247.5
);
-- 第五步,把1247.5进行替换
select last_name,salary,dept_id
from s_emp
where dept_id in(
    select dept_id
    from s_emp
    group by dept_id
    having avg(salary)>(
        select avg(salary)
        from s_emp
        where dept_id=41
    )
);

查询平均工资比41号部门的平均工资高的部门中员工的信息,并且显示出当前部门的平均工资

-- 第一步,查询平均工资比41号部门的平均工资高的部门中员工的信息
select last_name,salary,dept_id
from s_emp
where dept_id in(
    select dept_idfrom s_emp
    group by dept_id
    having avg(salary)>(
        select avg(salary)
        from s_emp
        where dept_id=41
    )
);

-- 第二步,查询每个部门的平均工资
select dept_id,avg(salary)
from s_emp
group by dept_id;

-- 第三步,把第二步的结果当做一个虚拟的表,在第一步的sql语句中,进行多表查询,等值连接的条件是俩张表的dept_id相等
select se.last_name,se.salary,se.dept_id,temp.avgSal
from s_emp se,(
    select dept_id,avg(salary) avgSal
    from s_emp
    group by dept_id) temp
    where se.dept_id in(
        select dept_id
        from s_emp
        group by dept_id
        having avg(salary)>(
            select avg(salary)
            from s_emp
            where dept_id=41
        )
    ) and se.dept_id = temp.dept_id;

分页查询

概述

实现分页的方式有很多,并且不同数据库,实现分页查询的方式也会不同,那么在Oracle中,可以使用伪列rownum,再结合子查询来进行简单的实现。

实现

rownum表示为一个查询的结果的行号,从1开始,连续不断

rownum当做条件查询时,只能:

  • 等于1
  • 大于0
  • 小于任何数

在这sql中,给rownum起一个别名rn,然后把这个sql语句作为第二条sql语句的子查询,并且把它当做一张虚拟的表,那么这时候,这个虚拟表中的rn是可以当做普通的字段进行操作了

select t.id,t.last_name,t.dept_id
from (
    select rownum rn,id,last_name,dept_id
    from s_emp
    where rownum<=10
) t
where t.rn>=6;

可以看出,这时候就查询出来s_emp表中的第610条数据,并且可以通过控制俩个参数,查询出表中任意的第mn条数据

思路:我们也可以通过minus方式 ,将第一个结果集除去第二个结果集和它相同的部分

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352