oracle窗口函数多列分区,oracle group by和窗口函数

一、group by

1、分组的实质就是一行(或多行)中的某一列(或多列)具有相同值。

2、组是非空的,如果分组成功,组至少包含一个成员(或行)。

3、组是独特的,意味着,当查询中使用group by时,select列表中就不必使用distinct关键字。

4、当针对非空表的查询(包含group by)中使用聚集函数count时,它绝对不会返回0。至少会返回一个非0值。

二、count(*)和count(列名)

create table fruits (name varchar2(10));

insert into fruits values ('Oranges');

insert into fruits values ('Oranges');

insert into fruits values ('Oranges');

insert into fruits values ('Apple');

insert into fruits values ('Peach');

insert into fruits values (null);

insert into fruits values (null);

insert into fruits values (null);

insert into fruits values (null);

insert into fruits values (null);

select name, count(name) from fruits group by name;

select name, count(*) from fruits group by name;

从例子可以看出,count(name)会忽略列的空值行,count(*)不会忽略空值行。

当使用count时,需要考虑是否希望包含NULL。使用count(column),不会计算NULL。

如果希望包含NULL,则使用count(*)对行计数。

三、select列表和group by子句

1、当使用聚集函数(如count)时,对于select列表中的项,如果没有把它当作聚集函数的参数使用,那么它必须是组的一部分。

2、对于可能对更改组(或更改聚集函数返回的值)的select列表项,一定包含于group by子句中。

3、问:select列表中的哪些项会更改组及聚集函数返回的值?

答:select对象表的其他列。不包含在select对象表中的列,可以出现在select后面。

四、窗口

与聚集函数一样,窗口函数也针对定义的行集(组)执行聚集,但它不像聚集函数那样每组只返回一个值,窗口函数可以为每组返回多个值。执行聚集的行组是窗口(因此命名为“窗口函数”)。

简单来说,窗口函数就是可以在每一行结果集后面加上一列,这一列就是聚集函数的执行结果。

如何使用窗口函数从细节行(每个员工一行)访问聚集数据(员工总数):

select ename,

deptno,

count(*) over() as cnt

from emp order by 2;

我理解为相当于在每一行后面开了一个窗口,窗口中能够访问聚集函数的结果。

ENAME DEPTNO CNT

---------- ---------- ----------

MILLER 10 19

CLARK 10 19

KING 10 19

JONES 20 19

TOM 20 19

SMITH 20 19

FORD 20 19

ADAMS 20 19

SCOTT 20 19

BLAKE 30 19

WARD 30 19

ALLEN 30 19

JAMES 30 19

MARTIN 30 19

TURNER 30 19

EAST 19

Jonathan 19

JACK 19

APPLE 19

在这个例子中,orver关键字表明:把count的调用看作窗口函数,而不是聚集函数。窗口函数count(*)over()对于查询返回的每一行,都返回了表中所有行的计数。

窗口函数是最后一步执行,(where和group by之后)仅在order by之前。所以where条件不同,窗口函数计算结果也不同。

五、分区

1、partition by可以在over关键字内表示分区或分组,以完成聚集。如果使用了空括号,那么整个结果集就是分区。

2、partition by对定义的行组计算聚集时,当遇到新组的时候会复位,并对每个组中的每个成员返回一个聚集的结果。

3、partition by字句和group by子句的运行方式一样,只是它不受select子句中的其他项影响,而且不需要编写group by子句。

select ename,

deptno,

count(*) over(partition by deptno) as cnt

from emp

order by 2;

ENAME DEPTNO CNT

---------- ---------- ----------

MILLER 10 3

CLARK 10 3

KING 10 3

JONES 20 6

TOM 20 6

SMITH 20 6

FORD 20 6

ADAMS 20 6

SCOTT 20 6

BLAKE 30 6

WARD 30 6

ALLEN 30 6

JAMES 30 6

MARTIN 30 6

TURNER 30 6

EAST 4

Jonathan 4

JACK 4

APPLE 4

partition by子句的优点是:在同一个select语句中,一个窗口函数的计算独立于按其他列分区的其他窗口函数的计算。

例如上面这个sql语句中,部门为10的单独计算了员工数,部分为20、30、空的同样单独计算了员工数。

查询sql,返回每个员工、他的部门、他的部门中的员工数、他的职位以及跟他相同职位的员工数:

select ename,

deptno,

count(*)over(partition by deptno) as dept_cnt,

job,

count(*)over(partition by job) as job_cnt

from emp;

4、与group by子句一样,partition by子句把所有的NULL合并为组或分区。

六、窗口函数和order by小子句

1、窗口函数可以在over子句内使用order by小子句,用于指定分区中行的排序方式。

2、如果没有partition by子句,就意味着处理整个结果集。也可以先partition by再order by。

3、有些窗口函数强制要求对分区中的行排序。因此,对于有些窗口函数,order by子句是必需的。

七、partition by和order by在over()中的使用

select deptno,

ename,

hiredate,

sal,

sum(sal)over(partition by deptno) as total1,

sum(sal)over() as total2,

sum(sal)over(order by hiredate) as running_total

from emp;

DEPTNO ENAME HIREDATESALTOTAL1 TOTAL2 RUNNING_TOTAL

---------- ---------- ------------------ ---------- ---------- ---------- -------------

20 SMITH 17-DEC-80 800 13875 32025 800

30 ALLEN 20-FEB-81 1600 9400 32025 2400

30 WARD 22-FEB-81 1250 9400 32025 3650

20 JONES 02-APR-81 2975 13875 32025 6625

30 BLAKE 01-MAY-81 2850 9400 32025 9475

10 CLARK 09-JUN-81 2450 8750 32025 11925

30 TURNER 08-SEP-81 1500 9400 32025 13425

30 MARTIN 28-SEP-81 1250 9400 32025 14675

10 KING 17-NOV-81 5000 8750 32025 19675

20 FORD 03-DEC-81 3000 13875 32025 23625

30 JAMES 03-DEC-81 950 9400 32025 23625

10 MILLER 23-JAN-82 1300 8750 32025 24925

20 TOM 01-JAN-86 3000 13875 32025 27925

20 SCOTT 19-APR-87 3000 13875 32025 30925

20 ADAMS 23-MAY-87 1100 13875 32025 32025

EAST 32025 32025

Jonathan 32025 32025

JACK 32025 32025

APPLE 32025 32025

从上面的例子可以看出:

partition by子句先按deptno分区,每个区都计算自己的sal总和。

order by子句,会在分区内指定一个默认的“移动”或“滑动”窗口。这里的分区是所有结果集,会按照当前行的hiredate位置终止总和的计算。形成累计的效果。

sum(sal)over(order by hiredate)

可以写成

sum(sal)over(order by hiredate

range between unbounded preceding and current row

)

八、其它

row_number()over()函数可以给,结果集增加一个行号

select empno, row_number()over(order by sal) rn from emp;

EMPNO RN

---------- ----------

7369 1

7900 2

7876 3

7521 4

7654 5

7934 6

7844 7

7499 8

7782 9

7698 10

7566 11

7788 12

7902 13

100 14

7839 15

9527 16

98 17

99 18

1 19

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值