当前位置: 首页 > 面试题库 >

将连续的日期有效期合并在一起

云星波
2023-03-14
问题内容

我有一系列记录,其中包含一些具有时间有效性的信息(产品类型)。

如果分组信息(产品类型)保持不变,我想将相邻的有效期合并在一起。我不能GROUP BYMIN和一起使用简单的方法MAX,因为某些产品类型(A在示例中为)可以“消失”和“返回”。

使用Oracle 11g。

输入数据

| PRODUCT |                       START_DATE |                         END_DATE |
|---------|----------------------------------|----------------------------------|
|       A |      July, 01 2013 00:00:00+0000 |      July, 31 2013 00:00:00+0000 |
|       A |    August, 01 2013 00:00:00+0000 |    August, 31 2013 00:00:00+0000 |
|       A | September, 01 2013 00:00:00+0000 | September, 30 2013 00:00:00+0000 |
|       B |   October, 01 2013 00:00:00+0000 |   October, 31 2013 00:00:00+0000 |
|       B |  November, 01 2013 00:00:00+0000 |  November, 30 2013 00:00:00+0000 |
|       A |  December, 01 2013 00:00:00+0000 |  December, 31 2013 00:00:00+0000 |
|       A |   January, 01 2014 00:00:00+0000 |   January, 31 2014 00:00:00+0000 |
|       A |  February, 01 2014 00:00:00+0000 |  February, 28 2014 00:00:00+0000 |
|       A |     March, 01 2014 00:00:00+0000 |     March, 31 2014 00:00:00+0000 |

预期结果

| PRODUCT |                      START_DATE |                         END_DATE |
|---------|---------------------------------|----------------------------------|
|       A |     July, 01 2013 00:00:00+0000 | September, 30 2013 00:00:00+0000 |
|       B |  October, 01 2013 00:00:00+0000 |  November, 30 2013 00:00:00+0000 |
|       A | December, 01 2013 00:00:00+0000 |     March, 31 2014 00:00:00+0000 |

请参阅完整的SQL Fiddle。


问题答案:

这是一个孤岛问题。有多种方法可以解决此问题。这使用leadlag分析功能:

select distinct product,
  case when start_date is null then lag(start_date)
    over (partition by product order by rn) else start_date end as start_date,
  case when end_date is null then lead(end_date)
    over (partition by product order by rn) else end_date end as end_date
from (
  select product, start_date, end_date, rn
  from (
    select t.product,
      case when lag(end_date)
          over (partition by product order by start_date) is null
        or lag(end_date)
          over (partition by product order by start_date) != start_date - 1
        then start_date end as start_date,
      case when lead(start_date)
          over (partition by product order by start_date) is null
        or lead(start_date)
          over (partition by product order by start_date) != end_date + 1
        then end_date end as end_date,
      row_number() over (partition by product order by start_date) as rn
    from t
  )
  where start_date is not null or end_date is not null
)
order by start_date, product;

PRODUCT START_DATE END_DATE
------- ---------- ---------
A       01-JUL-13  30-SEP-13 
B       01-OCT-13  30-NOV-13 
A       01-DEC-13  31-MAR-14

SQL小提琴

最里面的查询查看产品的前后记录,并且仅在记录不连续时才保留开始和/或结束时间:

select t.product,
  case when lag(end_date)
      over (partition by product order by start_date) is null
    or lag(end_date)
      over (partition by product order by start_date) != start_date - 1
    then start_date end as start_date,
  case when lead(start_date)
      over (partition by product order by start_date) is null
    or lead(start_date)
      over (partition by product order by start_date) != end_date + 1
    then end_date end as end_date
from t;

PRODUCT START_DATE END_DATE
------- ---------- ---------
A       01-JUL-13            
A                            
A                  30-SEP-13 
A       01-DEC-13            
A                            
A                            
A                  31-MAR-14 
B       01-OCT-13            
B                  30-NOV-13

select的下一个级别将删除那些处于中期的日期,其中两个日期都被内部查询所遮盖,从而得到:

PRODUCT START_DATE END_DATE
------- ---------- ---------
A       01-JUL-13            
A                  30-SEP-13 
A       01-DEC-13            
A                  31-MAR-14 
B       01-OCT-13            
B                  30-NOV-13

然后,外部查询会折叠那些相邻的对;我使用了创建重复项,然后使用消除重复项的简单distinct方法,但是您可以通过其他方式进行操作,例如将两个值都放入一对行中,并将两个值都保留为另一个空值,然后用另一个值消除它们选择层,但我认为在这里完全可以。

如果您的实际用例有时间,而不仅仅是日期,那么您需要在内部查询中调整比较;而不是+/-
1,可能是1秒的间隔,或者如果您愿意,则是1/86400,但取决于值的精度。



 类似资料:
  • 问题内容: 我有日期Ymd格式的数组,该格式可以是相隔一天的十个设置日期的任意组合。 例如:这是全套: 2011-01-01、2011-01-02、2011-01-03、2011-01-04、2011-01-05、2011-01-06、2011-01-07、2011-01-08、2011- 2011年1月9日至01日 从该集合创建的数组可以是日期的任何组合-所有日期,其中一个日期,一些连续日期,所

  • 问题内容: 我有一个表,每个月的每月(一年中的每个月)包含1条记录。我需要确定给定月份的站点是否至少有15个连续记录,并且我需要知道该连续天数的开始和结束日期。我可以在存储过程中执行此操作,但我希望可以在单个查询中完成此操作。我正在处理一个相当大的数据集,每月至少有3000万条记录。 结果示例: 感谢您的帮助! 问题答案: 这是有关如何执行此查询的示例: 然后查询: 结果: 问候,罗布。

  • 问题内容: 我正在针对从Excel文件导入的数据运行SQL语句。在此SQL中,我正在检查用户是否已使用IsDate函数正确输入了日期。由于这是尚未转换的原始数据,因此所有日期都存储在varchar数据类型字段中。 在某些情况下,如果用户输入的日期格式明显不正确,IsDate将返回1(有效日期)。 例如: 关于如何处理此问题的任何建议? 谢谢! ps Smacking用户没有帮助。 问题答案: 我做

  • 问题内容: 我在从表中显示正确的数据时遇到了麻烦。我不太确定要搜索什么。我不确定min(column)或max(column)在这里对我有帮助。让我们看看我是否可以解释我的问题。 我的表包含以下数据: 我将以一种观点来介绍这一点。它将按代码分组。 我想要的是此输出: 如您所见,DateTo和DateFrom之间是否存在间隙,我希望将其显示为两行。但是,如果具有相同代码的下一个“ DateFrom”

  • 我在Spring API的请求体中使用LocalDateTime。 当我在请求中输入无效日期时,例如“2020-02-31 00:00:00”,它会自动转换为“2020-02-29 00:00:00”。我想在无效日期的情况下抛出异常。官方留档中提到它会转换为以前的有效日期。

  • 问题内容: 有没有检查连续日期的功能。我在处理以下问题时遇到问题: 我的表有一个包含以下数据的列: 给定的开始日期为,结束日期为。我想要的结果是: 有人可以建议什么吗? 问题答案: 我认为这是 “连续日期分组岛” 问题的一种变体。可以使用以下方法完成: SQL小提琴 结果 这是SQL Server 2005版本: SQL小提琴