Oracle数仓中判断时间连续性的几种SQL写法

本文涉及的产品
云原生数据仓库AnalyticDB MySQL版,基础版 8ACU 100GB 1个月
简介: 零、需求介绍现有一张表数据如下:此表是一张镜像表,policyno列代表一个保单号,state列代表这个保单号在snapdate当天的最后一次状态(state每天可能会变很多次,镜像表只保留snapdate时间点凌晨的最后一次状态),snapdate代表当天做镜像的时间,现在有个需求,我们想取出来这个保单号连续保持某个状态的起止时间,例如:保单号sm1保持状态1的起止时间为2021020120210202,然后在20210203时候变成了状态2,又在20210204时候变成了状态3,最终又在202

零、需求介绍

现有一张表数据如下:
image.png

此表是一张镜像表,policyno列代表一个保单号,state列代表这个保单号在snapdate当天的最后一次状态(state每天可能会变很多次,镜像表只保留snapdate时间点凌晨的最后一次状态),
snapdate代表当天做镜像的时间,现在有个需求,我们想取出来这个保单号连续保持某个状态的起止时间,例如:
保单号sm1保持状态1的起止时间为20210201~20210202,然后在20210203时候变成了状态2,又在20210204时候变成了状态3,最终又在20210205~20210209时间段保持在状态1,
然后镜像表的程序可能期间出现过问题,在20210210开始到20210215日没有镜像成功,直到20210216日才恢复,20210216~20210219日保单号sm1的状态一直保持为1,
后续还有可能继续变,那么,上面说的保单sm1的几个状态的连续时间,我们想要的结果为:

POLICYNO    STATE    START_DATE    END_DATE
sm1        1    20210201    20210202
sm1        2    20210203    20210203
sm1        3    20210204    20210204
sm1        1    20210205    20210209
sm1     1      20210216       20210219
.........................

我这里提供5种写法,可以归结为两大类:
一类:通过使用分析函数或自关联获取数据连续性,构造一个分组字段进行分组求最大最小值。
二类:通过树形层次查询获取连续性,获取起止时间。

一、通过使用lag分析函数获取前后时间,根据当前时间与前后时间的差值进行判断获取时间连续性标志,然后使用sum()over()对连续性标志进行累加,从而生成一个新的临时分组字段,最终根据policyno,state,临时分组字段进行分组取最大最小值

这里为了好理解,每一个处理步骤都单独写出来了,实际使用中可以简写一下:

with t as--求出来每条数据当天的前一天镜像时间
 (select a.policyno,
         a.state,
         a.snapdate,
         lag(a.snapdate) over(partition by a.policyno, a.state order by a.snapdate) as lag_tim
    from zyd.temp_0430 a
   order by a.policyno, a.snapdate),
t1 as--判断当天镜像时间和前一天的镜像时间+1是否相等,如果相等就置为0否则置为1,新增临时字段lxzt意为:连续状态标志
 (select t.*,
         case
           when t.snapdate = t.lag_tim + 1 then
            0
           else
            1
         end as lxzt
    from t
   order by policyno, snapdate),
t2 as--根据lxzt字段进行sum()over()求和,求出来一个新的用来做分组依据的字段,简称fzyj
 (select t1.*, sum(lxzt) over(order by policyno, snapdate) as fzyj from t1)
select policyno,--最后根据policyno,state,fzyj进行分组求最大最小值即为状态连续的开始结束时间
       state,
       -- fzyj,
       min(snapdate) as start_snap,
       max(snapdate) as end_snap
  from t2
 group by policyno, state, fzyj
 order by fzyj;

image.png

二、不使用lag分析函数,通过自关联也能判断出来哪些天连续,然后后面操作步骤同上,这个写法算是对lag()over()函数的一个回写,摆脱对分析函数的依赖

下面这种写法,需要读两次表,上面lag的方式是对这个写法的一种优化:

with t as
 (select a.policyno, a.state, a.snapdate, b.snapdate as snap2
    from zyd.temp_0430 a, zyd.temp_0430 b
   where a.policyno = b.policyno(+)
     and a.state = b.state(+)
     and a.snapdate - 1 = b.snapdate(+)
   order by policyno, snapdate),
t1 as
 (select t.*,
         case
           when snap2 is null then
            1
           else
            0
         end as lxzt
    from t
   order by policyno, snapdate),
t2 as
 (select t1.*, sum(lxzt) over(order by policyno, snapdate) as fzyj
    from t1
   order by policyno, snapdate)
select policyno,
       state,
       fzyj,
       min(snapdate) as start_snap,
       max(snapdate) as end_snap
  from t2
 group by policyno, state, fzyj
 order by fzyj;

image.png

三、通过构造树形结构,确定根节点和叶子节点来获取状态连续的开始和结束时间

先按照数据的连续性构造显示每层关系的树状结构:

with t as
 (select a.policyno,
         a.state,
         a.snapdate,
         lag(a.snapdate) over(partition by a.policyno, a.state order by a.snapdate) as lag_tim
    from zyd.temp_0430 a --where policyno='sm1'
   order by a.policyno, a.snapdate),
t1 as
 (select t.*,
         case
           when t.snapdate = t.lag_tim + 1 then
            0
           else
            1
         end as lxzt
    from t
   order by policyno, snapdate),
t2 as
 (select t1.*,
         lpad('->', (level - 1) * 2, '->') || snapdate as 树状结构,
         level as 树中层次,
         decode(level, 1, 1) 是否根节点,
         decode(connect_by_isleaf, 1, 1) 是否叶子节点,
         case
           when (connect_by_isleaf = 0 and level > 1) then
            1
         end  是否树杈,
         (prior snapdate) as 根值,
         connect_by_root snapdate 主根值
    from t1
   start with (lxzt = 1)
  connect by (prior snapdate = snapdate - 1 
          and prior state = state and
              prior policyno = policyno)
   order by policyno, snapdate)
select * from t2;

image.png
从上面能清晰的看出来,每一次连续状态的开始日期作为每个树的根,分支节点即树杈和叶子节点的关系一步步拓展开来,分析上面数据我们能够知道,如果我们想要获取
每个保单状态连续时间范围,以上面的数据现有分布方式,现在就可以:通过policyno,state,主根值进行group by 取snapdate的最大最小值,类似前面两个写法的最终步骤;
接下来,我们这个第三种写法就是按照这个方式写:

with t as
 (select a.policyno,
         a.state,
         a.snapdate,
         lag(a.snapdate) over(partition by a.policyno, a.state order by a.snapdate) as lag_tim
    from zyd.temp_0430 a --where policyno='sm1'
   order by a.policyno, a.snapdate),
t1 as
 (select t.*,
         case
           when t.snapdate = t.lag_tim + 1 then
            0
           else
            1
         end as lxzt
    from t
   order by policyno, snapdate),
t2 as
 (select t1.*,
         lpad('->', (level - 1) * 2, '->') || snapdate as 树状结构,
         level as 树中层次,
         decode(level, 1, 1) 是否根节点,
         decode(connect_by_isleaf, 1, 1) 是否叶子节点,
         case
           when (connect_by_isleaf = 0 and level > 1) then
            1
         end  是否树杈,
         (prior snapdate) as 根值,
         connect_by_root snapdate 主根值
    from t1
   start with (lxzt = 1)
  connect by (prior snapdate = snapdate - 1 
          and prior state = state and
              prior policyno = policyno)
   order by policyno, snapdate)
select policyno,
       state,
       min(snapdate) as start_date,
       max(snapdate) as end_date
  from t2
 group by policyno, state, 主根值
 order by policyno, state;

image.png

四、参照过程三,既然已经获取了每条数据的主根值和叶子节点的值,这就代表了我们知道了每个保单状态的连续开始和结束时间,那直接取出来叶子节点数据,叶子节点主根值就是开始日期,叶子节点的值就是结束日期,这样我们就不需再group by了

with t as
 (select a.policyno,
         a.state,
         a.snapdate,
         lag(a.snapdate) over(partition by a.policyno, a.state order by a.snapdate) as lag_tim
    from zyd.temp_0430 a --where policyno='sm1'
   order by a.policyno, a.snapdate),
t1 as
 (select t.*,
         case
           when t.snapdate = t.lag_tim + 1 then
            0
           else
            1
         end as lxzt
    from t
   order by policyno, snapdate),
t2 as
 (select t1.*,
         lpad('->', (level - 1) * 2, '->') || snapdate as 树状结构,
         level as 树中层次,
         decode(level, 1, 1) 是否根节点,
         decode(connect_by_isleaf, 1, 1) 是否叶子节点,
         case
           when (connect_by_isleaf = 0 and level > 1) then
            1
         end 是否树杈,
         (prior snapdate) as 根值,
         connect_by_root snapdate 主根值
    from t1
   start with (lxzt = 1)
  connect by (prior snapdate = snapdate - 1 and prior state = state and
             prior policyno = policyno)
   order by policyno, snapdate)
select policyno, state, 主根值 as start_date, snapdate as end_date
  from t2
 where 是否叶子节点 = 1
 order by policyno, snapdate

image.png

五、在Oracle10g之前,上面树状查询的关键函数 connect_by_root还不支持,如果使用树形结构,可以通过sys_connect_by_path来实现

with t as
 (select a.policyno,
         a.state,
         a.snapdate,
         lag(a.snapdate) over(partition by a.policyno, a.state order by a.snapdate) as lag_tim
  --case when lag(a.snapdate) over(partition by a.policyno, a.state order by a.snapdate) is null then snapdate else lag(a.snapdate) over(partition by a.policyno, a.state order by a.snapdate) end as lag_tim
    from zyd.temp_0430 a
   order by a.policyno, a.snapdate),
t1 as
 (select t.*,
         case
           when t.snapdate = t.lag_tim + 1 then
            0
           else
            1
         end as lxzt
    from t
   order by policyno, snapdate),
t2 as
 (select t1.*,
         sys_connect_by_path(snapdate, ',') as pt,
         level,
         connect_by_isleaf as cb
    from t1
   start with (lxzt = 1)
  connect by (prior snapdate = snapdate - 1 and prior state = state and
             prior policyno = policyno))
select t2.*,
       regexp_substr(pt, '[^,]+', 1, 1) as start_date,
       regexp_substr(pt, '[^,]+', 1, regexp_count(pt, ',')) as end_date
  from t2
 where cb = 1
 order by policyno, state;

image.png
还有好多其他写法,这里不再一一列举,有兴趣的可以评论下面写出其他方案奥!

相关实践学习
AnalyticDB MySQL海量数据秒级分析体验
快速上手AnalyticDB MySQL,玩转SQL开发等功能!本教程介绍如何在AnalyticDB MySQL中,一键加载内置数据集,并基于自动生成的查询脚本,运行复杂查询语句,秒级生成查询结果。
阿里云云原生数据仓库AnalyticDB MySQL版 使用教程
云原生数据仓库AnalyticDB MySQL版是一种支持高并发低延时查询的新一代云原生数据仓库,高度兼容MySQL协议以及SQL:92、SQL:99、SQL:2003标准,可以对海量数据进行即时的多维分析透视和业务探索,快速构建企业云上数据仓库。 了解产品 https://www.aliyun.com/product/ApsaraDB/ads
相关文章
|
2月前
|
SQL 存储 OLAP
OneSQL OLAP实践问题之Flink SQL Gateway的功能如何解决
OneSQL OLAP实践问题之Flink SQL Gateway的功能如何解决
31 1
|
2月前
|
SQL 数据库
实时数仓 Hologres产品使用合集之如何找回之前的SQL查询代码
实时数仓Hologres是阿里云推出的一款高性能、实时分析的数据库服务,专为大数据分析和复杂查询场景设计。使用Hologres,企业能够打破传统数据仓库的延迟瓶颈,实现数据到决策的无缝衔接,加速业务创新和响应速度。以下是Hologres产品的一些典型使用场景合集。
|
3月前
|
SQL Oracle 关系型数据库
|
3月前
|
SQL Oracle 关系型数据库
MySQL、SQL Server和Oracle数据库安装部署教程
数据库的安装部署教程因不同的数据库管理系统(DBMS)而异,以下将以MySQL、SQL Server和Oracle为例,分别概述其安装部署的基本步骤。请注意,由于软件版本和操作系统的不同,具体步骤可能会有所变化。
170 3
|
3月前
|
SQL 存储 Oracle
TDengine 3.3.2.0 发布:新增 UDT 及 Oracle、SQL Server 数据接入
**TDengine 3.3.2.0 发布摘要** - 开源与企业版均强化性能,提升WebSocket、stmt模式写入与查询效率,解决死锁,增强列显示。 - taos-explorer支持geometry和varbinary类型。 - 企业版引入UDT,允许自定义数据转换。 - 新增Oracle和SQL Server数据接入。 - 数据同步优化,支持压缩,提升元数据同步速度,错误信息细化,支持表名修改。 - 扩展跨平台支持,包括麒麟、Euler、Anolis OS等。
97 0
|
4月前
|
SQL Cloud Native 关系型数据库
云原生数据仓库AnalyticDB操作报错合集之执行sql的进程报错:"unknown connection id",是什么导致的
阿里云AnalyticDB提供了全面的数据导入、查询分析、数据管理、运维监控等功能,并通过扩展功能支持与AI平台集成、跨地域复制与联邦查询等高级应用场景,为企业构建实时、高效、可扩展的数据仓库解决方案。以下是对AnalyticDB产品使用合集的概述,包括数据导入、查询分析、数据管理、运维监控、扩展功能等方面。
778 3
|
4月前
|
SQL Oracle 关系型数据库
一些非常有用的Oracle SQL
一些非常有用的Oracle SQL
40 4
|
4月前
|
SQL 弹性计算 分布式计算
实时数仓 Hologres操作报错合集之在执行SQL查询时遇到了问题,报错原因是“Invalid index column id: 2”,该怎么处理
在使用阿里云实时数仓Hologres时,可能会遇到不同类型的错误。例如:1.内存超限错误、2.字符串缓冲区扩大错误、3.分区导入错误、4.外部表访问错误、5.服务未开通或权限问题、6.数据类型范围错误,下面是一些常见错误案例及可能的原因与解决策略的概览。
|
29天前
|
存储 机器学习/深度学习 监控
阿里云 Hologres OLAP 解决方案评测
随着大数据时代的到来,企业面临着海量数据的挑战,如何高效地进行数据分析和决策变得尤为重要。阿里云推出的 Hologres OLAP(在线分析处理)解决方案,旨在为用户提供快速、高效的数据分析能力。本文将深入探讨 Hologres OLAP 的特点、优势以及应用场景,并针对方案的技术细节、部署指导、代码示例和数据分析需求进行评测。
78 7

热门文章

最新文章

推荐镜像

更多
下一篇
无影云桌面