【问题标题】:Extract time points meeting some time interval criteria提取满足某些时间间隔条件的时间点
【发布时间】:2019-04-29 14:59:30
【问题描述】:

我四处寻找并没有找到解决方案。 (有用的阅读SQL to find time elapsed from multiple overlapping intervals

这是我的数据:规则是

"对于每个国家,依次选择Date_ID,时间间隔等于或大于5个月"

我的工作环境是 ORACLE SQL。

非常感谢。

Country       Date_ID
----------------------
USA           199003
USA           200004
USA           200005
USA           200009
USA           200010
UK            199307
UK            199308
UK            199408

因此输出应该是

 Country    Date_ID
 --------------------
 USA        199003
 USA        200004
 USA        200009
 UK         199307
 UK         199408

【问题讨论】:

  • 您好,Jarlh,感谢您的评论。我不确定我的问题是否令人困惑。实际上我正在尝试选择“按顺序”的日期。以美国为例,1990/03 和 2000/04 的时间间隔大于 5 个月。但是,2000/05 到 2000/04 不在 5 个月内,因此没有选择 2000/05。
  • 您的 Oracle 版本是多少?这个问题在 Oracle 12.1 及更高版本中很容易解决,使用match_recognize;在旧版本中更难。
  • 另外,DATE_ID的数据类型是什么?它们是 字符串 还是属于正确的数据类型,即 date
  • @mathguy,你是对的......
  • @mathguy 我的预言机是 11.2 DATE_ID 是 NUMBER(6)。如果您知道此版本中的一些解决方案,那就太好了。如果没有,非常感谢 Oracle 12.1 或 Mysql.etc 中的任何建议/文档。

标签: sql oracle time aggregation


【解决方案1】:

这是解决此问题的一种方法,它至少可以追溯到 Oracle 10.2。它使用分析函数和分层查询。

WITH 子句只是用来动态构建示例数据。您不需要它 - 删除它,并在查询中使用您的实际表名和列名。 (在 WITH 子句中,我在 CTE 名称之后声明了列,这仅适用于 Oracle 11.2 及更高版本,但 WITH 子句不是解决方案的一部分,所以我不会担心。)

with
  sample_data (country, date_id) as (
    select 'USA', 199003 from dual union all
    select 'USA', 200004 from dual union all
    select 'USA', 200005 from dual union all
    select 'USA', 200009 from dual union all
    select 'USA', 200010 from dual union all
    select 'UK' , 199307 from dual union all
    select 'UK' , 199308 from dual union all
    select 'UK' , 199408 from dual
  )
select country, date_id
from   (
         select country, date_id,
                row_number() over (partition by country order by dt) as rn,
                count(*) over (partition by country order by dt
                  range between current row 
                            and interval '4' month following) as ct
         from   (
                  select country, date_id, 
                         to_date(to_char(date_id, 'fm999999'), 'yyyymm') as dt
                  from   sample_data
                )
       )
start with rn = 1
connect by country = prior country and rn = prior rn + prior ct
;

COUNTRY    DATE_ID
------- ----------
UK          199307
UK          199408
USA         199003
USA         200004
USA         200009

为了比较,这里有一个match_recognize 解决方案,需要Oracle 12.1 或更高版本:

select country, date_id
from   (
         select country, date_id, 
                to_date(to_char(date_id, 'fm999999'), 'yyyymm') dt
         from   sample_data
       )
match_recognize(
  partition by country
  order by     date_id
  all rows per match
  pattern      (a {- b* -})
  define b as  dt < add_months(a.dt, 5)
);

【讨论】:

  • 这正是我正在寻找的非常聪明的答案。我测试它并且它有效!我需要一些时间来消化它,并会及时更新。谢谢!
  • @user1503 - 在您研究解决方案时随时提出后续问题。
  • 嗨,Mathguy,非常感谢这个答案,我收集了很多有用的函数工具。但是,我最近遇到了一个似乎无法通过匹配识别解决的问题。看来滑动窗口是要走的路。我发布了问题stackoverflow.com/questions/55738319/… 看来我在这里的行为不适合再问你一个问题。如果是这样,我将删除此消息。一如既往的感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-30
  • 2020-07-13
  • 2018-08-26
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多