比较特定位置的两个日期之间的日期
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
条件的行的符号名称。 (所以,a
和 b
可以是 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 排序,然后在它们上运行您的代码。以上是关于比较特定位置的两个日期之间的日期的主要内容,如果未能解决你的问题,请参考以下文章