分析函数之分组排序
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> lag(arg1,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_rank与rank()用法相当,
【区别】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,
LEAD(EXPR,
【功能】表示根据COL1分组,在分组内部根据 COL2排序,而这个值就表示每组内部排序后的顺序编号(组内连续的唯一的)
lead () 下一个值 lag() 上一个值
【参数】
EXPR是从其他行返回的表达式
OFFSET是缺省为1 的正数,表示相对行数。希望检索的当前行分区的偏移量
DEFAULT是在OFFSET表示的数目超出了分组的范围时返回的值。
【说明】Oracle分析函数
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 |
倚天屠龙记 |
---查询所有姓名,如果同名则按年龄降序
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; 这种方法有个问题,就是max的age和max的details列不一定能匹配,正确的写法是只保留1列,要么age列要么details列,如果你是想获取max的age和max的details这当然是没有错的。
----跳跃查询
----先随便插入两条重复数据
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。
----连续排序,当有多个并列排序是,下一个任然连续有序
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。
Lag和Lead函数可以在一次查询中取出同一字段的前N行的数据和后N行的值。这种操作可以使用对相同表的表连接来实现,不过使用LAG和LEAD有更高的效率
Lag和Lead偏移量函数,其用途是:可以查出同一字段下一个值或上一个值,并作为新列存在表中
exp_str 返回显示的字段;
offset是exp_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",导致有错行。
exp_str 返回显示的字段;
offset是exp_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 |
(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 |
常见的分析函数如下:
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> over(order by salary) 按照salary排序进行累计,order by是个默认的开窗函数
over(partition by deptno)按照部门分区
2> over(order by salary range between 5 preceding and 5 following)
每行对应的数据窗口是之前行幅度值不超过5,之后行幅度值不超过5
3>over(order by salary rows between 2 preceding and 4 following)
每行对应的数据窗口是之前2行,之后4行
4>over(order by salary rows between unbounded preceding and unbounded following)
每行对应的数据窗口是从第一行到最后一行,等效:
over(order by salary range between unbounded preceding and unbounded following)
等效:
over(partition by null)
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 |
----按照月份,统计每个地区总收入
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 |
----按照月份,地区统计收入
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 |
----按照月份,地区进行收入总汇总
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 是分组函数,按照earnmonth和area先后次序分组。
以上三例都是先按照earnmonth分组,在earnmonth内部再按area分组,并在area组内统计personincome总合。
group by 后面什么也不接就是直接分组。
group by 后面接 rollup 是在纯粹的 group by 分组上再加上对earnmonth的汇总统计。
group by 后面接 cube 是对earnmonth汇总统计基础上对area再统计。
另外那个 nulls last 是把空值放在最后。
rollup和cube区别:
如果是ROLLUP(A, B, C)的话,GROUP BY顺序
(A、B、C)
(A、B)
(A)
最后对全表进行GROUP BY操作。
如果是GROUP BY CUBE(A, B, C),GROUP BY顺序
(A、B、C)
(A、B)
(A、C)
(A),
(B、C)
(B)
(C),
最后对全表进行GROUP BY操作。
在以上例子中,是用rollup和cube函数都会对结果集产生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 |
----按照月份、地区,求打工收入排序
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 |
----按照月份、地区,求打工收入排序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 |
----按照月份、地区,求打工收入排序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 |
通过(5)(6)(7)发现,结果集中如果出现两个相同的数据,那么rank会进行跳跃式的排名,比如两个第二,那么没有第三接下来就是第四;但是dense_rank不会跳跃式的排名,两个第二接下来还是第三;row_number最牛,即使两个数据相同,排名也不一样。
----根据月份求出各个打工者收入总和,按照收入由少到多排序。
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 |
----按照月份和地区求打工收入最高值,最低值,平均值和总额
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 |
----求出每个打工者上个月和下个月有没有挣钱(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 |
说明:Lag和Lead函数可以在一次查询中取出某个字段的前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/