在SQL中查找匹配间隔 - Oracle

dan*_*ang 10 sql oracle date

我有一张桌子:

表:

start         end
1 Jan 09    31 Jan 2009
1 Feb 09    28 Feb 2009
1 Mar 09    31 Mar 2009
1 Apr 09    01 May 2009
1 May 09    31 May 2009
1 Jun 09    01 Jul 2009
1 Jul 09    31 Jul 2009
1 Aug 09    31 Aug 2009
1 Sep 09    01 Oct 2009
1 Oct 09    31 Oct 2009
1 Nov 09    01 Dec 2009
1 Dec 09    31 Dec 2009
1 Jan 10    31 Jan 2010
1 Feb 10    03 Mar 2010
1 Mar 10    31 Mar 2010
1 Apr 10    01 May 2010
1 May 10    31 May 2010
1 Jun 10    01 Jul 2010
1 Jul 10    31 Jul 2010
1 Aug 10    31 Aug 2010
1 Sep 10    01 Oct 2010
1 Oct 10    31 Oct 2010
1 Nov 10    01 Dec 2010
1 Dec 10    31 Dec 2010
1 Jan 09    31 Mar 2009
1 Apr 09    30 Jun 2009
1 Jul 09    01 Oct 2009
1 Oct 09    31 Dec 2009
1 Jan 10    31 Mar 2010
1 Apr 10    30 Jun 2010
1 Jul 10    01 Oct 2010
1 Oct 10    31 Dec 2010
1 Jan 09    31 Dec 2009
1 Jan 10    31 Dec 2010
Run Code Online (Sandbox Code Playgroud)

以上内容包含2009年,2010年的每个月,每季度和每年.

我有另一张表,内容如下:

表2

start       end
15-12-09    31-12-09
15-01-12    31-12-13
01-01-11    31-12-13
30-01-98    31-12-13
01-01-98    31-12-13
01-01-98    31-12-13
23-12-12    31-12-13
12-11-11    31-12-13
01-01-10    31-12-13
Run Code Online (Sandbox Code Playgroud)

对于table2中的每个条目,我需要找到它落入table1的可能时间范围.

对于前者 来自table2,第一次进入 -

15-12-09    31-12-09
Run Code Online (Sandbox Code Playgroud)

落到:

1 Dec 09    31 Dec 2009
1 Oct 09    31 Dec 2009
1 Jan 09    31 Dec 2009
Run Code Online (Sandbox Code Playgroud)

在Oracle SQL中是否可以识别它?

Mar*_*ber 3

您必须首先定义table1间隔中的下降是什么意思

一般有两种可能的解释。更具限制性的是SUBINTERVAL,即匹配的间隔完全被参考间隔覆盖。

 match              <----------> 
 reference    <------------------>
Run Code Online (Sandbox Code Playgroud)

另一种更宽松的可能性是INTERSECT,这意味着两个间隔至少有一个共同点。

 match                       <----------> 
 reference   <------------------>
Run Code Online (Sandbox Code Playgroud)

根据该决定,您使用不同的连接条件。在下面的查询中,实现了第一种可能性,只需交换注释即可获得其他选项。

请注意,下面创建了包含模拟数据的表格。

select 
   tab2.start_d match_start, tab2.end_d match_end, 
   tab.start_d ref_start, tab.end_d ref_end 
from tab2 
join tab
-- option SUBINTERVAL
on tab.start_d <= tab2.start_d and tab2.end_d <= tab.end_d
-- option INTERSEC
--  on NOT (tab2.end_d <  tab.start_d OR tab2.start_d > tab.end_d)
order by 1,2,3;
Run Code Online (Sandbox Code Playgroud)

SUBINTERVAL 选项的结果

MATCH_START       MATCH_END         REF_START         REF_END         
----------------- ----------------- ----------------- -----------------
15.12.09 00:00:00 31.12.09 00:00:00 01.01.09 00:00:00 31.12.09 00:00:00 
15.12.09 00:00:00 31.12.09 00:00:00 01.10.09 00:00:00 31.12.09 00:00:00 
15.12.09 00:00:00 31.12.09 00:00:00 01.12.09 00:00:00 31.12.09 00:00:00  
Run Code Online (Sandbox Code Playgroud)

您将获得更多有关 INTERSECT 选项的记录。

这是测试数据

create table tab as
with tab as (
-- reference intervals
-- months
select add_months(to_date('01012009','ddmmyyyy'),rownum-1) start_d,
add_months(to_date('01012009','ddmmyyyy'),rownum)-1 end_d from dual connect by level <=24
union all
-- quartals
select add_months(to_date('01012009','ddmmyyyy'),3*(rownum-1)) start_d,
add_months(to_date('01012009','ddmmyyyy'),3*rownum)-1 end_d from dual connect by level <=24/3
union all
-- years
select add_months(to_date('01012009','ddmmyyyy'),12*(rownum-1)) start_d,
add_months(to_date('01012009','ddmmyyyy'),12*rownum)-1 end_d from dual connect by level <=24/12
) 
select * from tab;

create table tab2 as
with tab2 as (
-- matched intervals
select to_date('15-12-09','dd-mm-rr') start_d,     to_date('31-12-09','dd-mm-rr') end_d from dual union all
select to_date('15-01-12','dd-mm-rr') start_d,     to_date('31-12-13','dd-mm-rr') end_d from dual union all
select to_date('15-01-98','dd-mm-rr') start_d,     to_date('31-12-13','dd-mm-rr') end_d from dual
)
select * from tab2;
Run Code Online (Sandbox Code Playgroud)