sql - 仅针对特定记录按子句分组

标签 sql oracle oracle11g

我计划为客户展平我的开始结束日期,如下所示。如果日期范围是连续的,我将合并这些记录。否则我会保持原样 例如:

Input
Customer START END
A        2000  2001
A        2001  2007 
A        2009  2010
A        2011  2015

Expected Output
A        2000 2007
A        2009 2010
A        2011 2015

使用分析函数,我能够用连续日期标记记录:

--TAG = 1 means continuous
select A *,
CASE WHEN  LEAD (START) OVER (PARTITION BY CUSTOMER ORDER BY START,END) = END
OR LAG (END_DT) OVER (PARTITION BY CUSTOMER ORDER BY START,END) = START
THEN 1 ELSE 0 END AS CONT_FLG
From TABLE CUSTOMER  

Customer START END   CONT_FLG
A        2000  2001  1
A        2001  2007  1
A        2009  2010  0
A        2011  2015  0

但我无法继续按客户对 min (START) 和 mAx (END) 进行分组,因为它也会合并非连续值。有什么好的建议

最佳答案

如果您捕获实际的提前/滞后日期而不是 0/1,那么您会得到如下所示的结果:

select t.*,
  case when lag(end_dt) over (partition by customer order by start_dt)
    = start_dt then null else start_dt end as adj_start_dt,
  case when lead(start_dt) over (partition by customer order by start_dt)
    = end_dt then null else end_dt end as adj_end_dt
from t42 t
order by customer, start_dt;

CUSTOMER   START_DT     END_DT ADJ_START_DT ADJ_END_DT
-------- ---------- ---------- ------------ ----------
A              2000       2001         2000            
A              2001       2003                         
A              2003       2007                    2007 
A              2009       2010         2009       2010 
A              2011       2015         2011       2015 

为了达到效果,我已将您的第二条记录拆分为两个相邻的记录,因此此处有一行机器人调整的日期为空。然后,您可以删除那些都为空的记录,因为它们反射(reflect)完全在一个范围内的记录,并且您留下每个期间的开始和结束日期:

select *
from (
  select t.*,
    case when lag(end_dt) over (partition by customer order by start_dt)
      = start_dt then null else start_dt end as adj_start_dt,
    case when lead(start_dt) over (partition by customer order by start_dt)
      = end_dt then null else end_dt end as adj_end_dt
  from t42 t
)
where adj_start_dt is not null or adj_end_dt is not null
order by customer, start_dt;

CUSTOMER   START_DT     END_DT ADJ_START_DT ADJ_END_DT
-------- ---------- ---------- ------------ ----------
A              2000       2001         2000            
A              2003       2007                    2007 
A              2009       2010         2009       2010 
A              2011       2015         2011       2015 

然后您可以折叠那些带有空值的行,因为相邻行(带有超前/滞后)现在是相关的:

select distinct customer,
  case when adj_start_dt is null then
    lag(adj_start_dt) over (partition by customer order by start_dt)
    else adj_start_dt end as grp_start_dt,
  case when adj_end_dt is null then
    lead(adj_end_dt) over (partition by customer order by start_dt)
    else adj_end_dt end as grp_end_dt
from (
  select t.*,
    case when lag(end_dt) over (partition by customer order by start_dt)
      = start_dt then null else start_dt end as adj_start_dt,
    case when lead(start_dt) over (partition by customer order by start_dt)
      = end_dt then null else end_dt end as adj_end_dt
  from t42 t
)
where adj_start_dt is not null or adj_end_dt is not null
order by customer, grp_start_dt;

CUSTOMER GRP_START_DT GRP_END_DT
-------- ------------ ----------
A                2000       2007 
A                2009       2010 
A                2011       2015 

SQL Fiddle demo .

关于sql - 仅针对特定记录按子句分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27960180/

相关文章:

mysql - 查询合并相同列名的两个表

sql - 从 Oracle 表中获取值计数

sql - 将合并、计数、案例和子句组合在一起

sql - Oracle 计划将 'b' 与 'B' 998x 比较慢(10g 或 11g)

sql - 如果表为空,则将行插入表中,如果不在 SQLite 中,则替换现有行

sql - Oracle 如何将生成的列添加到选择 *

Oracle 在数据库驱动器空间达到临界水平时触发

c# - 删除 Oracle 中不存在的记录是否被认为是错误的形式?

oracle - ORA-12505,TNS :listener does not currently know of SID given in connect descriptor. Eclipse 和 Fedora 20 通过 JDBC

sql - 如何使用游标比较两个不同表的两列中的值