分段统计与Oracle的分析函数、逻辑判断等知识点的综合运用
2014-04-21 16:58
603 查看
重点部分:TOTAL层
项目要求:
统计每个巡检员(USER_ID)当前月的签到率及查询相关字段
签到率公式:以巡检员为单位,
(当月至今天为止签到的所有点/该月巡检点的总个数)=(b.Point/a.Total)
TOTAL相关更多要求:
①在使用过程中,巡检点个数会根据实际情况进行变更,例如2014年1月15日管理员给某一位巡检员安排5个点,10天后增加了2个点,即2014年1月24日以后按照7个点来统计,所以,如果当月更改多次的话,这个月会分成许多段。
②每一次更改有一个批次号,对应表T_SIGN_POINTS的POINT_DATE字段,这个字段的值设置为明天生效,即今日更改,明天生效。
③TOTAL公式:
假设有以下已知条件:
假设今天是2014年4月25日,USER_ID=1249,统计2014年4月的该巡检员应该巡查的点的总个数,T_SIGN_POINTS中相关批次有Batch2014.3.29=6个、Batch2014.4.5=8个,Batch2014.4.12=11个、Batch2014.4.26日=5个
则TOTAL的数学计算应该为:6个×4天+8个×11天+11个×13天=255个(另有其它一些边界情况类似)
这里需要考虑到多种可能性,即便只使用最理想的情况,将上面这个公式完全使用SQL语言完成,也是一个挺复杂的过程,相比之下,查询需要的字段后在后台做计算难度会降低,不过这种写法可以大幅提升对Oracle或者SQL语言的运用和理解,不排除Oracle有更合适的函数或更简洁的方法来解决类似问题。
相关表及字段情况:
表T_SIGN_RECORDS:记录该巡检员已签到的点
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/23026bd284376295a2691382e5672ad1.png)
表T_SIGN_POINTS:记录给每个巡检员安排的巡检点
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/d3e3f1d2a56bccd47047d979918252b2.png)
完整SQL语句:
注释:
【外围层】连接到:用户表(T_USER)、部门表(T_DEPARTMENT)、角色表(T_ROLE)查询一些字段 ,值得注意的是CASE WHEN THEN ELSE END和显示格式“|| '/' ||”的使用
【POINT层】一个简单的count函数的使用
【TOTAL层】是重点,由多层嵌套而成,接下来是各层的结果图片和知识点:
【TOTAL第0层】
结果图片:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/db9ec2d89e04afefd5dd4eef321d2b33.png)
SQL功能:查询并统计与当月相关的批次及各批次的点的个数
BatchNum为该批次的点的个数,
TMon为当月的月份,
BatchMon为批次号所在的月份,这个字段的值可以区分批次号是当月的还是本月之前的最大批次号,为的是辅助lead函数进行排序,如果批次号在当月,结果为当月的第2天,如果在这个月之前,返回当月的第1天
【TOTAL第1层】
结果图片:
TOTAL第1层内层结果
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/49e8d47a69e9871d1f0dff24b9ee9ae6.png)
TOTAL第1层外层结果:计算每一段的签到点的总个数
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/82ab918a5aad84399871deaabd64697a.png)
SQL功能:主要增加SEG_NEXT字段,将下一个批次号的日期做为SEG_NEXT
PARTITION以a.user_id为区域执行lead函数,按照a.batchDay和a.batchmon排序,这里可看出batchmon字段的意义:如果本月在2014年4月1号有批次号,就把小于本月的最大批次号放在4月1号批次号的下面,这样,结果图片中第9行batchDay和SEG_NEXT就都是都是1,两段的差值是0,不会影响后续的结果。
【TOTAL第2层】
结果图片
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/0a48639f8057a6461367594b7f9ff256.png)
SQL知识点:
Decode函数:
Decode函数可以与sigh函数和greatest函数结合使用,其中与greatest函数结合使用的时候,要注意参数的顺序和if_value和value的顺序,因为greatest的参数存在相等的情况,当参数相等的时候,会执行第一个if_value的value
2014-05-09
上面的SQL只能用在统计当月的情况,而且TMon和total最外层where语句有bug,后来项目中增加了一个按时间段查询的功能,将这些bug修正并总结了一个任意时间段通用版本。
接下来的这个SQL可用于任意时间段的情况,只需传入合适的参数即可,其中StartTime对应时间段的起点、EndTime对应时间段的终点,建议格式‘YYYY-MM-DD’,目前的代码使用了“+StartTime+”的形式,这样直接就可以复制粘贴到Flex的SQL字符串中使用,只需变量名一致即可。
这段SQL代码只是Total层(完整代码中已重命名为a层),如果想嵌入到最上面完整的代码,只需将完整代码的最后的b层更改为如下,其它不变
项目要求:
统计每个巡检员(USER_ID)当前月的签到率及查询相关字段
签到率公式:以巡检员为单位,
(当月至今天为止签到的所有点/该月巡检点的总个数)=(b.Point/a.Total)
TOTAL相关更多要求:
①在使用过程中,巡检点个数会根据实际情况进行变更,例如2014年1月15日管理员给某一位巡检员安排5个点,10天后增加了2个点,即2014年1月24日以后按照7个点来统计,所以,如果当月更改多次的话,这个月会分成许多段。
②每一次更改有一个批次号,对应表T_SIGN_POINTS的POINT_DATE字段,这个字段的值设置为明天生效,即今日更改,明天生效。
③TOTAL公式:
假设有以下已知条件:
假设今天是2014年4月25日,USER_ID=1249,统计2014年4月的该巡检员应该巡查的点的总个数,T_SIGN_POINTS中相关批次有Batch2014.3.29=6个、Batch2014.4.5=8个,Batch2014.4.12=11个、Batch2014.4.26日=5个
则TOTAL的数学计算应该为:6个×4天+8个×11天+11个×13天=255个(另有其它一些边界情况类似)
这里需要考虑到多种可能性,即便只使用最理想的情况,将上面这个公式完全使用SQL语言完成,也是一个挺复杂的过程,相比之下,查询需要的字段后在后台做计算难度会降低,不过这种写法可以大幅提升对Oracle或者SQL语言的运用和理解,不排除Oracle有更合适的函数或更简洁的方法来解决类似问题。
相关表及字段情况:
表T_SIGN_RECORDS:记录该巡检员已签到的点
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/23026bd284376295a2691382e5672ad1.png)
表T_SIGN_POINTS:记录给每个巡检员安排的巡检点
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/d3e3f1d2a56bccd47047d979918252b2.png)
完整SQL语句:
select * from (select a.*, case a.IS_LOGIN when 1 then '已登录' when 0 then '未登录' else '未登录' end as WEB_STATUS, case a.MOBILE_LOGIN when 1 then '已登录' when 0 then '未登录' else '未登录' end as MOBILE_STATUS, b.name as dep_name, b.parent_id, b.dep_level, c.name as role_name, c.order_index, c.function_no from t_user a, t_department b, t_role c where a.dep_id = b.id and a.role_id = c.id and IS_PATROL = 1) x left join (select a.user_id, (case when b.point is null then 0 else b.point end) || '/' || (a.total) as rate from (select user_id, sum(PartNum) as total /*【TOTAL第2层】开始*/ from (select user_id, /*【TOTAL第1层】开始*/ tday, batchnum, batchMon, batchDay, seg_Next, decode(seg_next, null, decode(greatest(batchday, tday), tday, (tday - batchday + 1) * batchnum, batchday, 0, null), decode(greatest(seg_next, tday), tday, (seg_next - batchday) * batchnum, seg_next, (tday - batchday + 1) * batchnum, null)) as PartNum from (SELECT a.user_id, a.tday, a.batchnum, a.batchMon, a.batchDay, lead(a.batchDay, 1, null) over(PARTITION BY a.user_id order by a.batchDay, a.batchmon) as seg_Next FROM (select t.user_id, /*【TOTAL第0层】开始*/ to_char((SELECT EXTRACT(MONTH FROM sysdate) FROM DUAL)) as TMon, (SELECT TRUNC(SYSDATE) FROM DUAL) as TDay, decode(sign(months_between(trunc(TO_DATE(t.points_date, 'YYYY-MM-DD'), 'MM'), trunc(sysdate, 'MM'))), 0, (select (trunc(TO_DATE(t.points_date, 'YYYY-MM-DD'), 'MM') + 1) from dual), -1, (select trunc(sysdate, 'MM') from dual), 1, (select (trunc(TO_DATE(t.points_date, 'YYYY-MM-DD'), 'MM') + 2) from dual)) as batchMon, decode(sign(months_between(trunc(TO_DATE(t.points_date, 'YYYY-MM-DD'), 'MM'), trunc(sysdate, 'MM'))), -1, (select trunc(sysdate, 'MM') from dual), TO_DATE(t.points_date, 'YYYY-MM-DD')) as batchDay, count(t.user_id) as BatchNum from T_SIGN_POINTS t where (to_date(t.points_date, 'YYYY-MM-DD') - (select trunc(sysdate, 'MM') from dual) >= 0) or (t.points_date = (select max(points_date) as EarlyMax from T_SIGN_POINTS where USER_ID = t.user_id and (to_date(points_date, 'YYYY-MM-DD') < (select trunc(sysdate, 'MM') from dual)) GROUP BY USER_ID)) group by t.user_id, t.points_date order by t.user_id desc, batchDay desc, batchmon desc) A /*【TOTAL第0层】结束*/ order by user_id desc, batchday desc, batchmon desc)) /*【TOTAL第1层】结束*/ group by user_id order by user_id desc) a /*【TOTAL第2层】结束*/ left join (select count(*) as point, user_id from t_sign_records sr where to_char(sign_time, 'yyyy-mm') = '2014-05' group by user_id) b on a.user_id = b.user_id) y on x.id = y.user_id order by order_index, user_id
注释:
【外围层】连接到:用户表(T_USER)、部门表(T_DEPARTMENT)、角色表(T_ROLE)查询一些字段 ,值得注意的是CASE WHEN THEN ELSE END和显示格式“|| '/' ||”的使用
【POINT层】一个简单的count函数的使用
【TOTAL层】是重点,由多层嵌套而成,接下来是各层的结果图片和知识点:
【TOTAL第0层】
结果图片:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/db9ec2d89e04afefd5dd4eef321d2b33.png)
SQL功能:查询并统计与当月相关的批次及各批次的点的个数
BatchNum为该批次的点的个数,
TMon为当月的月份,
BatchMon为批次号所在的月份,这个字段的值可以区分批次号是当月的还是本月之前的最大批次号,为的是辅助lead函数进行排序,如果批次号在当月,结果为当月的第2天,如果在这个月之前,返回当月的第1天
【TOTAL第1层】
结果图片:
TOTAL第1层内层结果
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/49e8d47a69e9871d1f0dff24b9ee9ae6.png)
TOTAL第1层外层结果:计算每一段的签到点的总个数
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/82ab918a5aad84399871deaabd64697a.png)
SQL功能:主要增加SEG_NEXT字段,将下一个批次号的日期做为SEG_NEXT
lead(a.batchDay, 1, 0) over(PARTITION BY a.user_id order by a.batchDay, a.batchmon) as seg_Next
PARTITION以a.user_id为区域执行lead函数,按照a.batchDay和a.batchmon排序,这里可看出batchmon字段的意义:如果本月在2014年4月1号有批次号,就把小于本月的最大批次号放在4月1号批次号的下面,这样,结果图片中第9行batchDay和SEG_NEXT就都是都是1,两段的差值是0,不会影响后续的结果。
【TOTAL第2层】
结果图片
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/05/0a48639f8057a6461367594b7f9ff256.png)
SQL知识点:
Decode函数:
decode(column,if_value,value,elseif_value,value,default_value); |
2014-05-09
上面的SQL只能用在统计当月的情况,而且TMon和total最外层where语句有bug,后来项目中增加了一个按时间段查询的功能,将这些bug修正并总结了一个任意时间段通用版本。
接下来的这个SQL可用于任意时间段的情况,只需传入合适的参数即可,其中StartTime对应时间段的起点、EndTime对应时间段的终点,建议格式‘YYYY-MM-DD’,目前的代码使用了“+StartTime+”的形式,这样直接就可以复制粘贴到Flex的SQL字符串中使用,只需变量名一致即可。
select user_id, sum(PartNum) as total from (select user_id, tday, batchnum, AidSort, batchDay, seg_Next, decode(seg_next, null, decode(greatest(batchday, tday), tday, (tday - batchday + 1) * batchnum, batchday, 0, null), decode(greatest(seg_next, tday), tday, (seg_next - batchday) * batchnum, seg_next, (tday - batchday + 1) * batchnum, null)) as PartNum from (SELECT a.user_id, a.tday, a.batchnum, a.AidSort, a.batchDay, lead(a.batchDay, 1, null) over(PARTITION BY a.user_id order by a.batchDay, a.AidSort) as seg_Next FROM (select t.user_id, TO_DATE('"+EndTime+"', 'YYYY-MM-DD') as TDay, decode((select (case when TO_DATE(t.points_date, 'YYYY-MM-DD') < (to_date('"+StartTime+"', 'YYYY-MM-DD')) then -1 when TO_DATE(t.points_date, 'YYYY-MM-DD') > TO_DATE('"+EndTime+"', 'YYYY-MM-DD') then 1 else 0 end) from dual), -1, 'AS1', 0, 'AS2', 'AS3') as AidSort, decode((select (case when TO_DATE(t.points_date, 'YYYY-MM-DD') < (TO_DATE('"+StartTime+"', 'YYYY-MM-DD')) then -1 when TO_DATE(t.points_date, 'YYYY-MM-DD') > TO_DATE('"+EndTime+"', 'YYYY-MM-DD') then 1 else 0 end) from dual), -1, TO_DATE('"+StartTime+"', 'YYYY-MM-DD'), TO_DATE(t.points_date, 'YYYY-MM-DD')) as batchDay, count(t.user_id) as BatchNum from T_SIGN_POINTS t where (t.points_date = (select min(points_date) as FutureMin from T_SIGN_POINTS where USER_ID = t.user_id and (to_date(points_date, 'YYYY-MM-DD') > TO_DATE('"+EndTime+"', 'YYYY-MM-DD')) GROUP BY USER_ID)) or (to_date(t.points_date, 'YYYY-MM-DD') between TO_DATE('"+StartTime+"', 'YYYY-MM-DD') and TO_DATE('"+EndTime+"', 'YYYY-MM-DD')) or (t.points_date = (select max(points_date) as EarlyMax from T_SIGN_POINTS where USER_ID = t.user_id and (to_date(points_date, 'YYYY-MM-DD') < TO_DATE('"+StartTime+"', 'YYYY-MM-DD')) GROUP BY USER_ID)) group by t.user_id, t.points_date order by t.user_id desc, batchDay desc, AidSort desc) A order by user_id desc, batchday desc, AidSort desc)) group by user_id order by user_id desc
这段SQL代码只是Total层(完整代码中已重命名为a层),如果想嵌入到最上面完整的代码,只需将完整代码的最后的b层更改为如下,其它不变
left join (select count(*) as point, user_id from t_sign_records sr where trunc(sign_time) between TO_DATE('2014-05-05', 'YYYY-MM-DD') and TO_DATE('2014-05-09', 'YYYY-MM-DD') group by user_id) b
相关文章推荐
- 教为学:Oracle SQL学习之路(四):分析函数之统计(二)
- oracle 统计分析函数
- 利用Oracle内置分析函数进行高效统计汇总
- oracle中LAG()和LEAD()等分析统计函数的使用方法(统计月增长率)
- oracle中LAG()和LEAD()等分析统计函数的用法
- 转:oracle 统计分析函数之lead
- 教为学:Oracle SQL学习之路(四):分析函数之统计(二)
- 利用Oracle内置分析函数进行高效统计汇总
- Oracle分析函数三、基于model函数建设口径统一的统计指标库
- oracle中LAG()和LEAD()等分析统计函数的使用方法(统计月增长率)
- oracle中LAG()和LEAD()等分析统计函数的用法(统计月增长率)
- oracle 统计分析函数之lead和lag
- Oracle分析函数——统计分析函数
- oracle中LAG()和LEAD()等分析统计函数的使用方法(统计月增长率)
- Oracle统计分析函数集之一(转载)
- Oracle之分析函数应用- 连续值判断
- 利用Oracle内置分析函数进行高效统计汇总(1)
- oracle 统计/分析函数
- ORACLE统计分析函数
- oracle 统计/分析函数