您的位置:首页 > 其它

【原创】分享一个分析函数统计案例

2013-12-27 16:12 337 查看
oracle数据仓库中提供了很多非常实用的函数,一直以来接触过,但是却没有实际的用到,因为尽管有示例,当时看懂了,但是后续马上就忘了,今天岑敏强遇到了一个使用over的场景,于是一起探讨了下,第一眼分析,我隐隐的就觉得一些分析函数应该会用到,但是没想到是over。
需求:

在 t_zxxm_fy 这个表中,有三个字段 n_lxsbh、n_fyje、n_mqzt,其中一个n_lxsbh会对应多个 n_ysje,每个n_mqzt都不一样,现在要统计几个n_lxsbh的 n_fyje之和,但每个n_lxsbh的n_ysje只能取一条记录的值,即n_ysje需要按n_mqzt进行某种排序取第一条记录


这个问题直白点说,就是将符合条件的记录按某n_lxsbh进行分组(如group by),然后对每个分组按n_mqzt进行排序,取分组的第一条记录中的n_fyje值。显然标准sql很难一条语句搞定,我尝试了下,写出来的sql很复杂,分组,嵌套,子查询而且还没完全搞定,如执行以下sql:

select n_lxsbh, n_fyje, n_mqzt
from t_zxxm_fy f
where n_fyje is not null --去掉n_fyje为空的值
and n_fyje <> 0 --去掉n_fyje为0的值
and n_lxsbh in (-999999999975037, -999999999937175, -999999999937891,
-999999999937695, -999999999937289) --要统计的lxsbh
order by n_lxsbh, n_mqzt desc


-----

N_LXSBH                                             N_FYJE            N_MQZT
1        -999999999975037                        1680774.28        6(命中)
2        -999999999975037                        966394.92          5
3        -999999999975037                        1276123.64        5
4        -999999999975037                        1119030.00        5

5        -999999999937891                        123727.27          3(命中)

6        -999999999937695                        2000.00              1(命中)

7        -999999999937289                        66137.81            3(命中)

8        -999999999937175                        81186.10            7(命中)
9        -999999999937175                        23739.54            2
10        -999999999937175                        96500.00          2
11        -999999999937175                        8798789.00       2
12        -999999999937175                        94200.00           2
13        -999999999937175                        195914.00          2


也就是说,最后统计出的结果集如下:

N_LXSBH                                               N_FYJE            N_MQZT
1        -999999999975037                        1680774.28            6(命中)
5        -999999999937891                        123727.27              3(命中)
6        -999999999937695                        2000.00                  1(命中)
7        -999999999937289                        66137.81                3(命中)
8        -999999999937175                        81186.10                7(命中)


下面给出实现上述结果集的sql(但不是该业务最终需要sql,最终的sql见文后):

select *
from (select t_zxxm_fy.n_lxsbh,
t_zxxm_fy.n_fyje,
row_number() over(partition by n_lxsbh order by n_mqzt desc) rn
from (select n_lxsbh, n_fyje, n_mqzt
from t_zxxm_fy f
where n_lxsbh in (-999999999975037, -999999999937289,
-999999999937695,-999999999937891, -999999999937175)
order by n_lxsbh, n_mqzt desc) t_zxxm_fy)
where rn = 1;


解释:由于统计中不可避免进行分组,因此,首先一个子查询:

(select n_lxsbh, n_fyje, n_mqzt
from t_zxxm_fy f
where n_lxsbh in (-999999999975037, -999999999937289,
-999999999937695,-999999999937891, -999999999937175)
order by n_lxsbh, n_mqzt desc) t_zxxm_fy)


也就是最内层的查询将结果集给限制住,减少外层查询需要处理的结果集,,然后外层查询:

select t_zxxm_fy.n_lxsbh,
t_zxxm_fy.n_fyje,
row_number() over(partition by n_lxsbh order by n_mqzt desc) rn
from(xxxxxxxx)


对该结果集进行over,简单说,就是上面的结果集以n_mqzt 进行排序后再以n_lxsbh进行分组(和group by类似但是也有区别,group by没组只能返回一条记录,但是这个partition却返回多条,仅仅是按某个字段分组而已,自己体会吧),分组之后的结果集状态如第一个结果集所示,row_number函数会为分组中的每条记录加一个行号,这个类似于rownum,如我将上面的rn=1限制去掉:

select *
from (select t_zxxm_fy.n_lxsbh,
t_zxxm_fy.n_fyje,
row_number() over(partition by n_lxsbh order by n_mqzt desc) rn
from (select n_lxsbh, n_fyje, n_mqzt from t_zxxm_fy f where n_lxsbh in (-999999999975037, -999999999937289, -999999999937695,-999999999937891, -999999999937175) order by n_lxsbh, n_mqzt desc) t_zxxm_fy)


---

N_LXSBH                                                N_FYJE               RN
1        -999999999975037                        1680774.28                 1
2        -999999999975037                        966394.92                   2
3        -999999999975037                        1276123.64                 3
4        -999999999975037                        1119030.00                 4
5        -999999999937891                        123727.27                   1
6        -999999999937695                        2000.00                       1
7        -999999999937289                        66137.81                     1
8        -999999999937175                        81186.10                     1
9        -999999999937175                        195914.00                   2
10        -999999999937175                        94200.00                   3
11        -999999999937175                        8798789.00               4
12        -999999999937175                        96500.00                   5
13        -999999999937175                        23739.54                   6


上述每个分组都给加了一个行号rn,好像group by做不到的,如果取第一行的话rn=1即可。
这样即完成了统计,功能是不是很强大?

下面就是性能了,最终的统计sql是这样写的:

select
(select sum(n_fyje)
from (select fy.n_lxsbh,
first_value(fy.n_fyje) over(partition by fy.n_lxsbh order by decode(N_MQZT, 3, 1, 7, 2, 6, 3, 1, 4)) as n_fyje
from t_zxxm_fy fy)
where n_lxsbh in
(select n_lxsbh from T_ZXXM_LXS t where t.n_mainxmbh = lxs.n_lxsbh)) as N_YGSSCB
from T_ZXXM_LXS lxs
where lxs.n_lxsbh = -999999999975037;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: