利用分析函数和开窗函数进行分组查询


分析函数之分组排序

1.分析函数释义

    row_number() OVER ( PARTITION BY COL1 ORDER BY COL2) 表示根据COL1分组,在分组内部根据 COL2排序,而此函数计算的值就表示每组内部排序后的顺序编号(组内连续的唯一的)

    rownum的区别在于:使用rownum进行排序的时候是先对结果集加入伪列rownum然后再进行排序,而此函数在包含排序从句后是先排序再计算行号码。

 

1> row_number()rownum差不多,功能更强一点(可以在各个分组内从1开时排序);

2> rank()是跳跃排序,有两个第二名时接下来就是第四名(同样是在各个分组内);

3> dense_rank() 是连续排序,有两个第二名时仍然跟着第三名。相比之下row_number是没有重复值的.

4> lagarg1,arg2,arg3):

     arg1是从其他行返回的表达式

     arg2是希望检索的当前行分区的偏移量。是一个正的偏移量,是一个往回检索以前的行的数目。

     arg3是在arg2表示的数目超出了分组的范围时返回的值。

 

函数语法:

OPAP函数语法四部分:

1.function 本身用于对窗口中的数据进行操作;

2.partitioning clause 用于将结果集分区;

3.order by clause 用于对分区中的数据进行排序;

4.windowing clause 用于定义function在其上操作的行的集合,即function所影响的范围;

 

 

rank()/dense_rank()

【语法】RANK ( ) OVER ( [query_partition_clause] order_by_clause )

        dense_RANK ( ) OVER ( [query_partition_clause] order_by_clause )

 

【功能】聚合函数RANK dense_rank 主要的功能是计算一组数值中的排序值。

【参数】dense_rankrank()用法相当,

【区别】dence_rank在并列关系是,相关等级不会跳过。rank则跳过

rank()是跳跃排序,有两个第二名时接下来就是第四名(同样是在各个分组内)

dense_rank()l是连续排序,有两个第二名时仍然跟着第三名。

【说明】Oracle分析函数

 

 

ROW_NUMBER()

【语法】ROW_NUMBER() OVER (PARTITION BY COL1 ORDER BY COL2)

【功能】表示根据COL1分组,在分组内部根据 COL2排序,而这个值就表示每组内部排序后的顺序编号(组内连续的唯一的)

row_number() 返回的主要是的信息,并没有排名

【参数】

【说明】Oracle分析函数

 

主要功能:用于取前几名,或者最后几名等

sum(...) over ...

【功能】连续求和分析函数

【参数】具体参示例

【说明】Oracle分析函数

lag()lead()

【语法】

lag(EXPR,,) OVER ( [query_partition_clause] order_by_clause )

LEAD(EXPR,,) OVER ( [query_partition_clause] order_by_clause )

【功能】表示根据COL1分组,在分组内部根据 COL2排序,而这个值就表示每组内部排序后的顺序编号(组内连续的唯一的)

lead () 下一个值 lag() 上一个值

 

【参数】

EXPR是从其他行返回的表达式

OFFSET是缺省为1 的正数,表示相对行数。希望检索的当前行分区的偏移量

DEFAULT是在OFFSET表示的数目超出了分组的范围时返回的值。

【说明】Oracle分析函数

 

 

2.环境准备

CREATE TABLE TEST_Y(

       ID VARCHAR2 (32) PRIMARY KEY ,

       NAME VARCHAR2 (20),

       AGE NUMBER(3 ),

       DETAILS VARCHAR2 (1000)

);

INSERT INTO TEST_Y VALUES(SYS_GUID(), '海子',20 ,'面朝大海,春暖花开');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '海子',30 ,'面朝大海,春暖花开');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '贝多芬',43 ,'致爱丽丝');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '普希金',34 ,'假如生活欺骗了你');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '杨过',23 ,'黯然销魂掌');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '小龙女',32 ,'神雕侠侣');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '李清照',21 ,'寻寻觅觅、冷冷清清');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '周芷若',18 ,'峨眉');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '赵敏',18 ,'自由');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '张无忌',20 ,'倚天屠龙记');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '张无忌',30 ,'倚天屠龙记');

commit;

SELECT * FROM TEST_Y;

ID

NAME

AGE

DETAILS

381C8AA6FE202CAEE0536F0BA8C0F22C

海子

20

面朝大海,春暖花开

381C8AA6FE212CAEE0536F0BA8C0F22C

海子

30

面朝大海,春暖花开

381C8AA6FE222CAEE0536F0BA8C0F22C

贝多芬

43

致爱丽丝

381C8AA6FE232CAEE0536F0BA8C0F22C

普希金

34

假如生活欺骗了你

381C8AA6FE242CAEE0536F0BA8C0F22C

杨过

23

黯然销魂掌

381C8AA6FE252CAEE0536F0BA8C0F22C

小龙女

32

神雕侠侣

381C8AA6FE262CAEE0536F0BA8C0F22C

李清照

21

寻寻觅觅、冷冷清清

381C8AA6FE272CAEE0536F0BA8C0F22C

周芷若

18

峨眉

381C8AA6FE282CAEE0536F0BA8C0F22C

赵敏

18

自由

381C8AA6FE292CAEE0536F0BA8C0F22C

张无忌

20

倚天屠龙记

381C8AA6FE2A2CAEE0536F0BA8C0F22C

张无忌

30

倚天屠龙记

 

3.row_number() over(partition by col1 order by col2)

---查询所有姓名,如果同名则按年龄降序

    select name,age,details,row_number() over(partition by name order by age desc) from test_y;

 

NAME

AGE

DETAILS

ROW_NUMBER()OVER(PARTITIONBYNA

贝多芬

43

致爱丽丝

1

海子

30

面朝大海,春暖花开

1

海子

20

面朝大海,春暖花开

2

李清照

21

寻寻觅觅、冷冷清清

1

普希金

34

假如生活欺骗了你

1

小龙女

32

神雕侠侣

1

杨过

23

黯然销魂掌

1

张无忌

30

倚天屠龙记

1

张无忌

20

倚天屠龙记

2

赵敏

18

自由

1

周芷若

18

峨眉

1

 

    通过上面的语句可知,row_number() over(partition by col1 order by col2)中是按照name字段分组,按age字段排序的。

 

    如果是只需要查询出不重复的姓名即可,则可以使用如下语句:

    select * from ( select name,age,details,(row_number() over(partition by name order by age desc)) as numid from test_y ) where numid=1;

 

NAME

AGE

DETAILS

NUMID

贝多芬

43

致爱丽丝

1

海子

30

面朝大海,春暖花开

1

李清照

21

寻寻觅觅、冷冷清清

1

普希金

34

假如生活欺骗了你

1

小龙女

32

神雕侠侣

1

杨过

23

黯然销魂掌

1

张无忌

30

倚天屠龙记

1

赵敏

18

自由

1

周芷若

18

峨眉

1

 

    由查询结果可知,姓名相同年龄小的数据备过略掉了。可以使用row_number() over(partition by col1 order by col2) 对部分子查询进行去重处理。

 

----上面查询还有种方法实现:select name,max(age),max (details) from test_y group by name; 这种方法有个问题,就是maxagemaxdetails列不一定能匹配,正确的写法是只保留1列,要么age列要么details列,如果你是想获取maxagemaxdetails这当然是没有错的。

 

 

4.rank() over(partition by col1 order by col2)

----跳跃查询

----先随便插入两条重复数据

INSERT INTO TEST_Y VALUES(SYS_GUID(), '普希金',34 ,'假如生活欺骗了你');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '杨过',23 ,'黯然销魂掌');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '普希金',34 ,'假如生活欺骗了你');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '杨过',23 ,'黯然销魂掌');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '普希金',39 ,'假如生活欺骗了你');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '杨过',29 ,'黯然销魂掌');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '普希金',40 ,'假如生活欺骗了你');

INSERT INTO TEST_Y VALUES(SYS_GUID(), '杨过',30 ,'黯然销魂掌');

commit;

 

 

    select name,age,details,rank() over (partition by name order by age) from test_y;

 

NAME

AGE

DETAILS

RANK()OVER(PARTITIONBYNAMEORDE

贝多芬

43

致爱丽丝

1

海子

20

面朝大海,春暖花开

1

海子

30

面朝大海,春暖花开

2

李清照

21

寻寻觅觅、冷冷清清

1

普希金

34

假如生活欺骗了你

1

普希金

34

假如生活欺骗了你

1

普希金

34

假如生活欺骗了你

1

普希金

39

假如生活欺骗了你

4

普希金

40

假如生活欺骗了你

5

小龙女

32

神雕侠侣

1

杨过

23

黯然销魂掌

1

杨过

23

黯然销魂掌

1

杨过

23

黯然销魂掌

1

杨过

29

黯然销魂掌

4

杨过

30

黯然销魂掌

5

张无忌

20

倚天屠龙记

1

张无忌

30

倚天屠龙记

2

赵敏

18

自由

1

周芷若

18

峨眉

1

 

    由查询结果可知,相同的并列,下一个则跳跃到并列所在的序号后。如果两个并列1,那么下一个则直接排为3,跳过2

 

 

5.dense_rank() over(partition by col1 order by col2)

----连续排序,当有多个并列排序是,下一个任然连续有序

    select name,age,details,dense_rank() over (partition by name order by age ) from test_y;

 

NAME

AGE

DETAILS

DENSE_RANK()OVER(PARTITIONBYNA

贝多芬

43

致爱丽丝

1

海子

20

面朝大海,春暖花开

1

海子

30

面朝大海,春暖花开

2

李清照

21

寻寻觅觅、冷冷清清

1

普希金

34

假如生活欺骗了你

1

普希金

34

假如生活欺骗了你

1

普希金

34

假如生活欺骗了你

1

普希金

39

假如生活欺骗了你

2

普希金

40

假如生活欺骗了你

3

小龙女

32

神雕侠侣

1

杨过

23

黯然销魂掌

1

杨过

23

黯然销魂掌

1

杨过

23

黯然销魂掌

1

杨过

29

黯然销魂掌

2

杨过

30

黯然销魂掌

3

张无忌

20

倚天屠龙记

1

张无忌

30

倚天屠龙记

2

赵敏

18

自由

1

周芷若

18

峨眉

1

 

    由查询结果可知,当两个并列为1时,下一个任然连续有序为2,不跳跃到3

 

 

6.lag(exp_str,offset,defval) over(partition by name order by age)

    Lag和Lead函数可以在一次查询中取出同一字段的前N行的数据和后N行的值。这种操作可以使用对相同表的表连接来实现,不过使用LAG和LEAD有更高的效率

     Lag和Lead偏移量函数,其用途是:可以查出同一字段下一个值或上一个值,并作为新列存在表中

 

    exp_str 返回显示的字段;

    offsetexp_str字段的偏移量,默认是1,如offset=1 表示返回当前exp_str的下一个exp_str

    defval 当该函数无值可用的情况下返回改值。

 

(1)

    select name,age,details,lag(name,2,'zhong') over (partition by name order by age desc) from test_y;

 

NAME

AGE

DETAILS

LAG(NAME,2,'ZHONG')OVER(PARTIT

贝多芬

43

致爱丽丝

zhong

海子

30

面朝大海,春暖花开

zhong

海子

20

面朝大海,春暖花开

zhong

李清照

21

寻寻觅觅、冷冷清清

zhong

普希金

40

假如生活欺骗了你

zhong

普希金

39

假如生活欺骗了你

zhong

普希金

34

假如生活欺骗了你

普希金

普希金

34

假如生活欺骗了你

普希金

普希金

34

假如生活欺骗了你

普希金

小龙女

32

神雕侠侣

zhong

杨过

30

黯然销魂掌

zhong

杨过

29

黯然销魂掌

zhong

杨过

23

黯然销魂掌

杨过

杨过

23

黯然销魂掌

杨过

杨过

23

黯然销魂掌

杨过

张无忌

30

倚天屠龙记

zhong

张无忌

20

倚天屠龙记

zhong

赵敏

18

自由

zhong

周芷若

18

峨眉

zhong

 

(2)

    select name,age,details,lag(name,2,'zhong') over ( order by age desc) from test_y;

NAME

AGE

DETAILS

LAG(NAME,2,'ZHONG')OVER(ORDERB

贝多芬

43

致爱丽丝

zhong

普希金

40

假如生活欺骗了你

zhong

普希金

39

假如生活欺骗了你

贝多芬

普希金

34

假如生活欺骗了你

普希金

普希金

34

假如生活欺骗了你

普希金

普希金

34

假如生活欺骗了你

普希金

小龙女

32

神雕侠侣

普希金

杨过

30

黯然销魂掌

普希金

海子

30

面朝大海,春暖花开

小龙女

张无忌

30

倚天屠龙记

杨过

杨过

29

黯然销魂掌

海子

杨过

23

黯然销魂掌

张无忌

杨过

23

黯然销魂掌

杨过

杨过

23

黯然销魂掌

杨过

李清照

21

寻寻觅觅、冷冷清清

杨过

张无忌

20

倚天屠龙记

杨过

海子

20

面朝大海,春暖花开

李清照

赵敏

18

自由

张无忌

周芷若

18

峨眉

海子

    上面的这个查询没有用分组,直接进行排序,然后在最大的年纪出插入两行"zhong",导致有错行。

 

 

7.lead(exp_str,offset,defval) over (partition by name order by age)

    exp_str 返回显示的字段;

    offsetexp_str字段的偏移量,默认是1,如offset=1 表示返回当前exp_str的下一个exp_str

    defval 当该函数无值可用的情况下返回改值。

 

(1)

    select name,age,details,lead(name,2,'zhong') over (partition by name order by age desc) from test_y;

 

NAME

AGE

DETAILS

LEAD(NAME,2,'ZHONG')OVER(PARTI

贝多芬

43

致爱丽丝

zhong

海子

30

面朝大海,春暖花开

zhong

海子

20

面朝大海,春暖花开

zhong

李清照

21

寻寻觅觅、冷冷清清

zhong

普希金

40

假如生活欺骗了你

普希金

普希金

39

假如生活欺骗了你

普希金

普希金

34

假如生活欺骗了你

普希金

普希金

34

假如生活欺骗了你

zhong

普希金

34

假如生活欺骗了你

zhong

小龙女

32

神雕侠侣

zhong

杨过

30

黯然销魂掌

杨过

杨过

29

黯然销魂掌

杨过

杨过

23

黯然销魂掌

杨过

杨过

23

黯然销魂掌

zhong

杨过

23

黯然销魂掌

zhong

张无忌

30

倚天屠龙记

zhong

张无忌

20

倚天屠龙记

zhong

赵敏

18

自由

zhong

周芷若

18

峨眉

zhong

 

(2)

    select name,age,details,lead(name,2,'zhong') over ( order by age desc) from test_y;

NAME

AGE

DETAILS

LEAD(NAME,2,'ZHONG')OVER(ORDER

贝多芬

43

致爱丽丝

普希金

普希金

40

假如生活欺骗了你

普希金

普希金

39

假如生活欺骗了你

普希金

普希金

34

假如生活欺骗了你

普希金

普希金

34

假如生活欺骗了你

小龙女

普希金

34

假如生活欺骗了你

杨过

小龙女

32

神雕侠侣

海子

杨过

30

黯然销魂掌

张无忌

海子

30

面朝大海,春暖花开

杨过

张无忌

30

倚天屠龙记

杨过

杨过

29

黯然销魂掌

杨过

杨过

23

黯然销魂掌

杨过

杨过

23

黯然销魂掌

李清照

杨过

23

黯然销魂掌

张无忌

李清照

21

寻寻觅觅、冷冷清清

海子

张无忌

20

倚天屠龙记

赵敏

海子

20

面朝大海,春暖花开

周芷若

赵敏

18

自由

zhong

周芷若

18

峨眉

zhong

 

 

8.sum(col1) over([partition by col2] [order by col3])

(1)

    select name,age,details,row_number() over(partition by name order by age desc),sum (age) over(partition by name order by age desc) from test_y;

 

NAME

AGE

DETAILS

ROW_NUMBER()OVER(PARTITIONBYNA

SUM(AGE)OVER(PARTITIONBYNAMEOR

贝多芬

43

致爱丽丝

1

43

海子

30

面朝大海,春暖花开

1

30

海子

20

面朝大海,春暖花开

2

50

李清照

21

寻寻觅觅、冷冷清清

1

21

普希金

40

假如生活欺骗了你

1

40

普希金

39

假如生活欺骗了你

2

79

普希金

34

假如生活欺骗了你

3

181

普希金

34

假如生活欺骗了你

4

181

普希金

34

假如生活欺骗了你

5

181

小龙女

32

神雕侠侣

1

32

杨过

30

黯然销魂掌

1

30

杨过

29

黯然销魂掌

2

59

杨过

23

黯然销魂掌

3

128

杨过

23

黯然销魂掌

4

128

杨过

23

黯然销魂掌

5

128

张无忌

30

倚天屠龙记

1

30

张无忌

20

倚天屠龙记

2

50

赵敏

18

自由

1

18

周芷若

18

峨眉

1

18

 

 

(2)

    select name,age,details,row_number() over(partition by name order by age desc),sum (age) over(partition by name) from test_y;

 

NAME

AGE

DETAILS

ROW_NUMBER()OVER(PARTITIONBYNA

SUM(AGE)OVER(PARTITIONBYNAME)

贝多芬

43

致爱丽丝

1

43

海子

30

面朝大海,春暖花开

1

50

海子

20

面朝大海,春暖花开

2

50

李清照

21

寻寻觅觅、冷冷清清

1

21

普希金

40

假如生活欺骗了你

1

181

普希金

39

假如生活欺骗了你

2

181

普希金

34

假如生活欺骗了你

3

181

普希金

34

假如生活欺骗了你

4

181

普希金

34

假如生活欺骗了你

5

181

小龙女

32

神雕侠侣

1

32

杨过

30

黯然销魂掌

1

128

杨过

29

黯然销魂掌

2

128

杨过

23

黯然销魂掌

3

128

杨过

23

黯然销魂掌

4

128

杨过

23

黯然销魂掌

5

128

张无忌

30

倚天屠龙记

1

50

张无忌

20

倚天屠龙记

2

50

赵敏

18

自由

1

18

周芷若

18

峨眉

1

18

 

 

(3)  nulls last 是把空值放在最后的意思

    select name,age,details,row_number() over(partition by name order by age desc),sum (age) over(order by age desc nulls last) from test_y;

 

NAME

AGE

DETAILS

ROW_NUMBER()OVER(PARTITIONBYNA

SUM(AGE)OVER(ORDERBYAGEDESCNUL

贝多芬

43

致爱丽丝

1

43

普希金

40

假如生活欺骗了你

1

83

普希金

39

假如生活欺骗了你

2

122

普希金

34

假如生活欺骗了你

5

224

普希金

34

假如生活欺骗了你

4

224

普希金

34

假如生活欺骗了你

3

224

小龙女

32

神雕侠侣

1

256

海子

30

面朝大海,春暖花开

1

346

张无忌

30

倚天屠龙记

1

346

杨过

30

黯然销魂掌

1

346

杨过

29

黯然销魂掌

2

375

杨过

23

黯然销魂掌

5

444

杨过

23

黯然销魂掌

4

444

杨过

23

黯然销魂掌

3

444

李清照

21

寻寻觅觅、冷冷清清

1

465

海子

20

面朝大海,春暖花开

2

505

张无忌

20

倚天屠龙记

2

505

赵敏

18

自由

1

541

周芷若

18

峨眉

1

541

 

 

(4)

    select name,age,details,sum(age) over() from test_y;

 

NAME

AGE

DETAILS

SUM(AGE)OVER()

海子

20

面朝大海,春暖花开

541

海子

30

面朝大海,春暖花开

541

贝多芬

43

致爱丽丝

541

普希金

34

假如生活欺骗了你

541

杨过

23

黯然销魂掌

541

小龙女

32

神雕侠侣

541

李清照

21

寻寻觅觅、冷冷清清

541

周芷若

18

峨眉

541

赵敏

18

自由

541

张无忌

20

倚天屠龙记

541

张无忌

30

倚天屠龙记

541

普希金

34

假如生活欺骗了你

541

杨过

23

黯然销魂掌

541

普希金

34

假如生活欺骗了你

541

杨过

23

黯然销魂掌

541

普希金

39

假如生活欺骗了你

541

杨过

29

黯然销魂掌

541

普希金

40

假如生活欺骗了你

541

杨过

30

黯然销魂掌

541

 

 

9.分析函数over与开窗函数

常见的分析函数如下:

row_number() over(partition by ... order by ...)

rank() over(partition by ... order by ...)

dense_rank() over(partition by ... order by ...)

count() over(partition by ... order by ...)

max() over(partition by ... order by ...)

min() over(partition by ... order by ...)

sum() over(partition by ... order by ...)

avg() over(partition by ... order by ...)

first_value() over(partition by ... order by ...)

last_value() over(partition by ... order by ...)

lag() over(partition by ... order by ...)

lead() over(partition by ... order by ...)

 

开窗函数:

    开窗函数指定了分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化,举例如下:

1> overorder by salary) 按照salary排序进行累计,order by是个默认的开窗函数   

   overpartition by deptno)按照部门分区

2> overorder by salary range between 5 preceding and 5 following

   每行对应的数据窗口是之前行幅度值不超过5,之后行幅度值不超过5

3>overorder by salary rows between 2 preceding and 4 following

每行对应的数据窗口是之前2行,之后4 

4>overorder by salary rows between unbounded preceding and unbounded following

每行对应的数据窗口是从第一行到最后一行,等效:

overorder by salary range between unbounded preceding and unbounded following

等效:

over(partition by null)

 

 

10.分析函数与开窗函数示列二:

----环境准备:

create table earnings -- 打工赚钱表  

(  

  earnmonth varchar2(6), -- 打工月份  

  area varchar2(20), -- 打工地区  

  sno varchar2(10), -- 打工者编号  

  sname varchar2(20), -- 打工者姓名  

  times int, -- 本月打工次数  

  singleincome number(10,2), -- 每次赚多少钱  

  personincome number(10,2) -- 当月总收入  

)  

 

insert into earnings values('200912','北平','511601','大魁',11,30,11*30);  

insert into earnings values('200912','北平','511602','大凯',8,25,8*25);  

insert into earnings values('200912','北平','511603','小东',30,6.25,30*6.25);  

insert into earnings values('200912','北平','511604','大亮',16,8.25,16*8.25);  

insert into earnings values('200912','北平','511605','贱敬',30,11,30*11);  

  

insert into earnings values('200912','金陵','511301','小玉',15,12.25,15*12.25);  

insert into earnings values('200912','金陵','511302','小凡',27,16.67,27*16.67);  

insert into earnings values('200912','金陵','511303','小妮',7,33.33,7*33.33);  

insert into earnings values('200912','金陵','511304','小俐',0,18,0);  

insert into earnings values('200912','金陵','511305','雪儿',11,9.88,11*9.88);  

  

insert into earnings values('201001','北平','511601','大魁',0,30,0);  

insert into earnings values('201001','北平','511602','大凯',14,25,14*25);  

insert into earnings values('201001','北平','511603','小东',19,6.25,19*6.25);  

insert into earnings values('201001','北平','511604','大亮',7,8.25,7*8.25);  

insert into earnings values('201001','北平','511605','贱敬',21,11,21*11);  

  

insert into earnings values('201001','金陵','511301','小玉',6,12.25,6*12.25);  

insert into earnings values('201001','金陵','511302','小凡',17,16.67,17*16.67);  

insert into earnings values('201001','金陵','511303','小妮',27,33.33,27*33.33);  

insert into earnings values('201001','金陵','511304','小俐',16,18,16*18);  

insert into earnings values('201001','金陵','511305','雪儿',11,9.88,11*9.88);  

commit;

 

----表内容如下:

SELECT * FROM earnings;

 

EARNMONTH

AREA

SNO

SNAME

TIMES

SINGLEINCOME

PERSONINCOME

200912

北平

511601

大魁

11

30.00

330.00

200912

北平

511602

大凯

8

25.00

200.00

200912

北平

511603

小东

30

6.25

187.50

200912

北平

511604

大亮

16

8.25

132.00

200912

北平

511605

贱敬

30

11.00

330.00

200912

金陵

511301

小玉

15

12.25

183.75

200912

金陵

511302

小凡

27

16.67

450.09

200912

金陵

511303

小妮

7

33.33

233.31

200912

金陵

511304

小俐

0

18.00

0.00

200912

金陵

511305

雪儿

11

9.88

108.68

201001

北平

511601

大魁

0

30.00

0.00

201001

北平

511602

大凯

14

25.00

350.00

201001

北平

511603

小东

19

6.25

118.75

201001

北平

511604

大亮

7

8.25

57.75

201001

北平

511605

贱敬

21

11.00

231.00

201001

金陵

511301

小玉

6

12.25

73.50

201001

金陵

511302

小凡

17

16.67

283.39

201001

金陵

511303

小妮

27

33.33

899.91

201001

金陵

511304

小俐

16

18.00

288.00

201001

金陵

511305

雪儿

11

9.88

108.68

 

1> sum函数,统计总和

----按照月份,统计每个地区总收入

select earnmonth,area,sum(personincome) from earnings group by earnmonth,area;

 

EARNMONTH

AREA

SUM(PERSONINCOME)

200912

北平

1179.5

201001

北平

757.5

201001

金陵

1653.48

200912

金陵

975.83

 

2> rollup函数

----按照月份,地区统计收入

select earnmonth,area,sum(personincome) from earnings group by rollup(earnmonth,area);

 

EARNMONTH

AREA

SUM(PERSONINCOME)

200912

北平

1179.5

200912

金陵

975.83

200912

 

2155.33

201001

北平

757.5

201001

金陵

1653.48

201001

 

2410.98

 

 

4566.31

 

3> cube函数

----按照月份,地区进行收入总汇总

select earnmonth,area,sum(personincome) from earnings group by cube(earnmonth,area) order by earnmonth,area nulls last;

 

EARNMONTH

AREA

SUM(PERSONINCOME)

200912

北平

1179.5

200912

金陵

975.83

200912

 

2155.33

201001

北平

757.5

201001

金陵

1653.48

201001

 

2410.98

 

北平

1937

 

金陵

2629.31

 

 

4566.31

 

----小结:

    sum是统计求和的函数。

    group by 是分组函数,按照earnmontharea先后次序分组。

    以上三例都是先按照earnmonth分组,在earnmonth内部再按area分组,并在area组内统计personincome总合。

 

group by 后面什么也不接就是直接分组。

group by 后面接 rollup 是在纯粹的 group by 分组上再加上对earnmonth的汇总统计。

group by 后面接 cube 是对earnmonth汇总统计基础上对area再统计。

另外那个 nulls last 是把空值放在最后。 

 

rollupcube区别:

如果是ROLLUP(A, B, C)的话,GROUP BY顺序

(ABC)

(AB)

(A)

最后对全表进行GROUP BY操作。

 

如果是GROUP BY CUBE(A, B, C)GROUP BY顺序

(ABC)

(AB)

(AC)

(A)

(BC)

(B)

(C)

最后对全表进行GROUP BY操作。

 

 

4> grouping函数

    在以上例子中,是用rollupcube函数都会对结果集产生null,这时候可用grouping函数来确认,该记录是由哪个字段得出来的

    grouping函数用法,带一个参数,参数为字段名,结果是根据该字段得出来的就返回1,反之返回0

select decode(grouping(earnmonth),1,'所有月份',earnmonth) 月份,

          decode(grouping(area),1,'全部地区',area) 地区,

          sum(personincome) 总金额

      from earnings

          group by cube(earnmonth,area)

          order by earnmonth,area nulls last;

 

月份

地区

总金额

200912

北平

1179.5

200912

金陵

975.83

200912

全部地区

2155.33

201001

北平

757.5

201001

金陵

1653.48

201001

全部地区

2410.98

所有月份

北平

1937

所有月份

金陵

2629.31

所有月份

全部地区

4566.31

 

 

5> rank() over开窗函数

----按照月份、地区,求打工收入排序

select earnmonth 月份,area 地区,sname 打工者,personincome 收入,

        rank() over(partition by earnmonth,area order by personincome desc) 排名

     from earnings;

 

月份

地区

打工者

收入

排名

200912

北平

大魁

330.00

1

200912

北平

贱敬

330.00

1

200912

北平

大凯

200.00

3

200912

北平

小东

187.50

4

200912

北平

大亮

132.00

5

200912

金陵

小凡

450.09

1

200912

金陵

小妮

233.31

2

200912

金陵

小玉

183.75

3

200912

金陵

雪儿

108.68

4

200912

金陵

小俐

0.00

5

201001

北平

大凯

350.00

1

201001

北平

贱敬

231.00

2

201001

北平

小东

118.75

3

201001

北平

大亮

57.75

4

201001

北平

大魁

0.00

5

201001

金陵

小妮

899.91

1

201001

金陵

小俐

288.00

2

201001

金陵

小凡

283.39

3

201001

金陵

雪儿

108.68

4

201001

金陵

小玉

73.50

5

 

 

6> dense_rank() over开窗函数

----按照月份、地区,求打工收入排序2

select earnmonth 月份,area 地区,sname 打工者,personincome 收入,

        dense_rank() over(partition by earnmonth,area order by personincome desc) 排名

     from earnings;

 

月份

地区

打工者

收入

排名

200912

北平

大魁

330.00

1

200912

北平

贱敬

330.00

1

200912

北平

大凯

200.00

2

200912

北平

小东

187.50

3

200912

北平

大亮

132.00

4

200912

金陵

小凡

450.09

1

200912

金陵

小妮

233.31

2

200912

金陵

小玉

183.75

3

200912

金陵

雪儿

108.68

4

200912

金陵

小俐

0.00

5

201001

北平

大凯

350.00

1

201001

北平

贱敬

231.00

2

201001

北平

小东

118.75

3

201001

北平

大亮

57.75

4

201001

北平

大魁

0.00

5

201001

金陵

小妮

899.91

1

201001

金陵

小俐

288.00

2

201001

金陵

小凡

283.39

3

201001

金陵

雪儿

108.68

4

201001

金陵

小玉

73.50

5

 

 

7> row_number() over开窗函数

----按照月份、地区,求打工收入排序3

select earnmonth 月份,area 地区,sname 打工者,personincome 收入,

        row_number() over(partition by earnmonth,area order by personincome desc) 排名

     from earnings;

 

月份

地区

打工者

收入

排名

200912

北平

大魁

330.00

1

200912

北平

贱敬

330.00

2

200912

北平

大凯

200.00

3

200912

北平

小东

187.50

4

200912

北平

大亮

132.00

5

200912

金陵

小凡

450.09

1

200912

金陵

小妮

233.31

2

200912

金陵

小玉

183.75

3

200912

金陵

雪儿

108.68

4

200912

金陵

小俐

0.00

5

201001

北平

大凯

350.00

1

201001

北平

贱敬

231.00

2

201001

北平

小东

118.75

3

201001

北平

大亮

57.75

4

201001

北平

大魁

0.00

5

201001

金陵

小妮

899.91

1

201001

金陵

小俐

288.00

2

201001

金陵

小凡

283.39

3

201001

金陵

雪儿

108.68

4

201001

金陵

小玉

73.50

5

 

 

----rank,dense_rank,row_number的区别:

    通过(5)(6)(7)发现,结果集中如果出现两个相同的数据,那么rank会进行跳跃式的排名,比如两个第二,那么没有第三接下来就是第四;但是dense_rank不会跳跃式的排名,两个第二接下来还是第三;row_number最牛,即使两个数据相同,排名也不一样。

 

 

8> sum累计求和

----根据月份求出各个打工者收入总和,按照收入由少到多排序。

select earnmonth 月份,area 地区,sname 打工者,personincome 收入,

        sum(personincome) over(partition by earnmonth,area order by personincome) 总收入

     from earnings;

 

月份

地区

打工者

收入

总收入

200912

北平

大亮

132.00

132

200912

北平

小东

187.50

319.5

200912

北平

大凯

200.00

519.5

200912

北平

大魁

330.00

1179.5

200912

北平

贱敬

330.00

1179.5

200912

金陵

小俐

0.00

0

200912

金陵

雪儿

108.68

108.68

200912

金陵

小玉

183.75

292.43

200912

金陵

小妮

233.31

525.74

200912

金陵

小凡

450.09

975.83

201001

北平

大魁

0.00

0

201001

北平

大亮

57.75

57.75

201001

北平

小东

118.75

176.5

201001

北平

贱敬

231.00

407.5

201001

北平

大凯

350.00

757.5

201001

金陵

小玉

73.50

73.5

201001

金陵

雪儿

108.68

182.18

201001

金陵

小凡

283.39

465.57

201001

金陵

小俐

288.00

753.57

201001

金陵

小妮

899.91

1653.48

 

 

9> max,min.avg和sum函数综合运用

----按照月份和地区求打工收入最高值,最低值,平均值和总额

select distinct earnmonth 月份,area 地区,

          max(personincome) over(partition by earnmonth,area) 最高值,

          min(personincome) over(partition by earnmonth,area) 最低值,

          avg(personincome) over(partition by earnmonth,area) 平均值,

          sum(personincome) over(partition by earnmonth,area) 总额

     from earnings;

 

月份

地区

最高值

最低值

平均值

总额

200912

金陵

450.09

0

195.166

975.83

201001

北平

350

0

151.5

757.5

200912

北平

330

132

235.9

1179.5

201001

金陵

899.91

73.5

330.696

1653.5

 

 

10> lag和lead函数

----求出每个打工者上个月和下个月有没有挣钱(personincome大于零为挣钱)

select earnmonth 本月,sname 打工者,

          lag(decode(nvl(personincome,0),0,'没挣','挣了'),1,0) over (partition by sname order by earnmonth) 上月,

          lead(decode(nvl(personincome,0),0,'没挣','挣了'),1,0) over(partition by sname order by earnmonth) 下月

     from earnings; 

 

本月

打工者

上月

下月

200912

大凯

0

挣了

201001

大凯

挣了

0

200912

大魁

0

没挣

201001

大魁

挣了

0

200912

大亮

0

挣了

201001

大亮

挣了

0

200912

贱敬

0

挣了

201001

贱敬

挣了

0

200912

小东

0

挣了

201001

小东

挣了

0

200912

小凡

0

挣了

201001

小凡

挣了

0

200912

小俐

0

挣了

201001

小俐

没挣

0

200912

小妮

0

挣了

201001

小妮

挣了

0

200912

小玉

0

挣了

201001

小玉

挣了

0

200912

雪儿

0

挣了

201001

雪儿

挣了

0

 

 

说明:LagLead函数可以在一次查询中取出某个字段的前N行和后N行的数据(可以是其他字段的数据,比如根据字段甲查询上一行或下两行的字段乙),原来没有分析函数的时候采用子查询方法,但是比较麻烦。

 

语法如下:

lag(value_expression [,offset] [,default]) over ([query_partition_clase] order_by_clause)

lead(value_expression [,offset] [,default]) over ([query_partition_clase] order_by_clause)

其中:

value_expression:可以是一个字段或一个内建函数。

offset是正整数,默认为1,指往前或往后几点记录.因组内第一个条记录没有之前的行,最后一行没有之后的行,

default就是用于处理这样的信息,默认为空。

 

    再讲讲所谓的开窗函数,开窗函数就是 over([query_partition_clase] order_by_clause)。比如说,我采用sum求和,rank排序等等,但是我根据什么来呢?over提供一个窗口,可以根据什么什么分组,就用partition by,然后在组内根据什么什么进行内部排序,就用 order by

 

 

 

 

 

 

 

 

 

reference     http://blog.csdn.net/yinshan33/article/details/18738229

http://www.cnblogs.com/Ronger/archive/2011/12/28/2304900.html

http://love-flying-snow.iteye.com/blog/573083

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30130773/viewspace-2122594/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30130773/viewspace-2122594/

你可能感兴趣的:(利用分析函数和开窗函数进行分组查询)