2015-12-09 5 views
10

私はテーブルを持っている:SQLでの間隔に一致する検索 - オラクル

テーブル:

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 

上記は、各月の2009年の四半期と年が含まれている、2010年

を、私は別のものを持っています次の表で:

table2の

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 

table2の各エントリについて、table1に入る可能性のあるタイムフレームを見つける必要があります。

例:表2から、最初のエントリ -

15-12-09 31-12-09 

はに落ちる:

1 Dec 09 31 Dec 2009 
1 Oct 09 31 Dec 2009 
1 Jan 09 31 Dec 2009 

はそれを識別するために、Oracle SQLで可能ですか?

+1

可能であれば、挿入スクリプトを提供できますか? – Buddi

+0

一方の表の終了日が他方の表の開始日以降か、表内の開始日が他の表の終了日より前かまたは等しいレコードを戻します。 – Rabbit

+0

Marmite Bomberの答えは、両方のシナリオで正しい回答を提供します... – dnoeth

答えて

2

あなたはまず、あなたが一般的な2つの可能な解釈があります。表1に間隔

で何を意味するか定義する必要があります。より限定的なものは、SUBINTERVAL, であり、すなわち、一致した間隔は基準間隔で完全に覆われている。

match    <----------> 
reference <------------------> 

他のよりリラックスした可能性は、両方の間隔に共通する少なくとも1つの点があることを意味INTERSECTあります。

match      <----------> 
reference <------------------> 

異なる結合条件を使用します。 以下のクエリでは、最初の可能性が実装されています。単純なコメントを交換して他のオプションを取得します。

ここでは、シミュレーションされたデータを含むテーブルが作成されています。部分区間オプション

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 

のためにあなたはINTERSECTオプションのはるかに多くのレコードを取得します

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; 

結果。

そして、ここでのテストデータは

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; 
+0

私は15-01-12から15-01-98のtab2を変更すると失敗します。 – dang

+0

@dang何が失敗するのですか?間隔15-01-98〜31-12-13は 'tab'の間隔には含まれていません。そのため、クエリはSTARTとENDの列にNULLを返します。私はこの新しい行を 'tab2'に追加しました –

+0

select to_date('15 -01-12 '、' dd-mm-rr ')start_d、to_date('31 -12-13'、 'dd-mm-rr ')end_dをdualから選択するto_date('15 -01-98'、 'dd-mm-rr')start_d、to_date('31 -12-13 '、' dd-mm-rr ')end_dからdual、it私にNULLを与えます – dang

1

まずあなたがクエリに変換されないようにあなたは、標準のDATE形式ですべてのものを保存する場合は、人生はそんなに単純になります。次にパターンは単純です:

WHERE table2.start <= table1.end 
    AND table1.start <= table2.end 
2

シンプルな間に役立ちます。

最初に2つのステートメントを使用して、table1のタイムフレーム内のtable2のstart_dateがtable2のend_dateがtable1の同じタイムフレーム内にあるかどうかをチェックします。両方のチェックは同時に保持する必要がありますので、それらを使用する必要があります。また

、方法は以下の動作「の間の」包括的である:それは>又は=をチェックし、最初のパラメータ および第二パラメータ<又は=ため。

ので、次の文があるに等しい:

t2.start_date between t1.start_date and t1.end_date 

t2.start_date >= t1.start_date and t2.start_date <= t1.end_date 

あなたが探しているSQLには、次のことになります。SQLで

select t2.*, '->', t1.* from table2 t2, 
    table1 t1 
    where t2.start_date between t1.start_date and t1.end_date 
    and t2.end_date between t1.start_date and t1.end_date 
1

を、表現するための最良の方法私が見つけた間隔の交差点は:

select * 
from table2 
join table1 
on 
    table1.start between table2.start and table2.end 
    or 
    table2.start between table1.start and table1.end; 

いずれの場合も、これらの2つの条件のいずれかに該当します。

1

私は

with days (dt, max_dt) as 
    (select (select min(start_dt) from table2) as dt 
     ,(select max(end_dt) from table2) as max_dt 
    from dual 
    union all 
    select dt+1 as dt 
     ,max_dt as max_dt 
    from days 
    where dt <max_dt 
) 
select distinct 
     t2.start_dt as start_dt2 
     ,t2.end_dt as end_dt2 
     ,t.start_dt as start_dt 
     ,t.end_dt as end_dt 
from table2 t2 
join days d on (t2.start_dt <=d.dt and t2.end_dt >= d.dt) 
join table t on (t.start_dt <=d.dt and t.end_dt >= d.dt) 

)=素晴らしいパフォーマンスせずに非常に単純な方法を選択しなかった私は、以下の例をカバーしよう:

table interval  |---------| 
table2 interval |---------------| 
table2 interval   |----| 
table2 interval    |--------| 
table2 interval |-----| 
0

私は本当にあなたが何を意味するか知っていると何をしたかったしません。ここに達成するが、これがあなたに役立つことを願っています。どういうわけか、私はあなたが参照していた出力を得ることができました(部分的に)。このコードをちょっと微調整してください。 TBL1、TBL2 場合(CONVERT(DATE、tbl2.START)> = CONVERT(DATE、tbl1.START))AND (CONVERT(DATE、TBL2 [END])< = CONVERT FROM

SELECT CONVERT(VARCHAR(25),CONVERT(DATE,tbl1.START)) 'start', 
    CONVERT(VARCHAR(25),CONVERT(DATE,tbl1.[END])) 'end', 
    CONVERT(VARCHAR(25),CONVERT(DATE,tbl2.START)) + ' - ' + CONVERT(VARCHAR(25),CONVERT(DATE,tbl2.[END])) 'table2' 

( DATE、tbl1。[END]))

関連する問題