比较特定位置的两个日期之间的日期

Posted

技术标签:

【中文标题】比较特定位置的两个日期之间的日期【英文标题】:Compare dates between two dates at specific positions 【发布时间】:2020-05-01 01:54:41 【问题描述】:

鉴于表中的以下示例记录:MY_DATES,使用 Oracle SQL 和/或 PL/SQL,我需要始终获取此表中的第一个 DATE_REGISTERED,即 26/10/2019 和然后前进到第三个 DATE_REGISTERED 记录/值,即 2/02/2020 并检查它们之间的差异是否大于 13 周,即

select to_date('2/02/2020','dd/mm/yyyy') - to_date('26/10/2019','dd/mm/yyyy') a from dual

Table Name: MY_DATES

NM  DATE_REGISTERED
--- ---------------
A1  26/10/2019
A1  2/11/2019
A1  2/02/2020
A1  9/02/2020
A1  16/02/2020
A1  23/02/2020
A1  1/03/2020
A1  8/03/2020

本练习的最终结果是返回满足此条件的不同 NM 值数据。

【问题讨论】:

说明所需的输出会有所帮助。解释逻辑很好,但它本身并不能告诉我们你需要什么结果。另外,NM在其中扮演什么角色?我假设您正在查看由 NM 分区的数据,但我在您的问题中没有看到任何相关内容。 @mathguy 我已经根据所寻求的最终结果对我的问题进行了更新。 另一个问题在我解决问题时变得明显。如果 NM 在表中只有两行,并且日期相隔超过 13 周怎么办?它们甚至没有 三个 日期,因此从您的描述看来,它们不应包含在输入中。这是正确的问题陈述吗? 【参考方案1】:

这是一个使用 MATCH_RECOGNIZE 子句的有效解决方案,在 Oracle 版本 12.1 中引入。

WITH 子句模拟输入数据(它不是解决方案的一部分 - 删除它并在主查询中引用您的实际表和列名称)。

解决方案按 NM 分区,按 DT 排序,然后查找第三个日期比第一个日期晚 13 周以上的三个连续行。一旦它发现一个这样的事件,它就会用分区中所有剩余的行填充“匹配模式”,基本上把它们扔掉——因为我们只关心一个匹配。

注意我添加的两个 NM。 BB 确实有相隔超过 13 周的日期,但不在连续三个日期之内。 CC 有两个连续的日期已经相隔超过 13 周; CC 不在输出中,因为没有三个不同的日期开始。 (注意 - 这就是我阅读要求的方式;如果需要的是“相隔 13 周以上的连续日期也应该计算在内”,这可以很容易地解决 - 但这不是发帖人问题中的措辞。)

with
  my_dates (nm, date_registered) as (
    select 'A1', to_date('26/10/2019', 'dd/mm/yyyy') from dual union all
    select 'A1', to_date( '2/11/2019', 'dd/mm/yyyy') from dual union all
    select 'A1', to_date( '2/02/2020', 'dd/mm/yyyy') from dual union all
    select 'A1', to_date( '9/02/2020', 'dd/mm/yyyy') from dual union all
    select 'A1', to_date('16/02/2020', 'dd/mm/yyyy') from dual union all
    select 'A1', to_date('23/02/2020', 'dd/mm/yyyy') from dual union all
    select 'A1', to_date( '1/03/2020', 'dd/mm/yyyy') from dual union all
    select 'A1', to_date( '8/03/2020', 'dd/mm/yyyy') from dual union all
    select 'BB', to_date( '2/03/2019', 'dd/mm/yyyy') from dual union all
    select 'BB', to_date('14/03/2019', 'dd/mm/yyyy') from dual union all
    select 'BB', to_date('18/03/2019', 'dd/mm/yyyy') from dual union all
    select 'BB', to_date('10/06/2019', 'dd/mm/yyyy') from dual union all
    select 'BB', to_date( '3/04/2019', 'dd/mm/yyyy') from dual union all
    select 'CC', to_date('15/08 2019', 'dd/mm/yyyy') from dual union all
    select 'CC', to_date('15/02/2020', 'dd/mm/yyyy') from dual
  )
-- end of sample data (for testing only); query begins below this comment
select nm
from   my_dates
match_recognize(
  partition by nm
  order     by date_registered
  pattern   ( a b c x* )
  define    c as date_registered > a.date_registered + 91
);



NM
----
A1

** 编辑 **

重新阅读问题,似乎只应考虑前三个日期(而不是任何三个连续的日期)。

这使问题更简单。并且解决方案可以轻松修改 - 唯一需要更改的是 pattern 子句,它应该变成:

pattern ( ^ a b c )

这会将搜索锚定在分区开头的三行。不检查其他行。

【讨论】:

没错,我将始终查看前三个日期(如果每个 NM 都存在),然后想看看是否有 13 周的差异。基于这个@mathguy,我现在需要为此使用模式 (^ a b c) - 对吗? @tonyf - 是的,正确的。如果您不熟悉 match_recognize 但您使用正则表达式:match_recognize 的工作原理相同,但它正在寻找“行”而不是“字符”。 a, b, c 是满足 define 条件的行的符号名称。 (所以,ab 可以是 any 行。)^ 是分区开头的锚点。 感谢您向我介绍 Oracle 的 MATCH_RECOGNIZE 子句。【参考方案2】:

这似乎很奇怪。我在想lead()lag)。如果您想要满足条件的nm 值:

select md.*
from (select md.*,
             lead(date_registered, 2) over (partition by nm order by date_registered) as next_dr_2,
             lag(date_registered) over (partition by nm order by date_registered) as prev_dr
      from my_dates md
     ) md
where prev_dr is null and
      next_dr_2 > date_registered + interval '91' day;

【讨论】:

这是正确的 - 我需要在满足此条件的情况下返回不同的 NM 值。 太好了 - 谢谢。现在的问题是我需要提供所有 MY_DATES 记录,即 nm/date_registered recs 作为一个组按 nm 并按 date_registered asc 排序,然后在它们上运行您的代码。

以上是关于比较特定位置的两个日期之间的日期的主要内容,如果未能解决你的问题,请参考以下文章

两个日期之间的Sqlite比较[重复]

获取不同记录的总和并在两个日期范围之间进行比较

比较特定时间间隔的不同格式的纪元日期

VB.net 创建日期 Killswitch(比较两个日期)

如何使用mysql计算两个日期之间的时间差

mysql日期范围查找(两个日期之间的记录)