code

SQL - Oracle에서 일치하는 간격 찾기

starcafe 2023. 10. 5. 23:25
반응형

SQL - Oracle에서 일치하는 간격 찾기

테이블이 있습니다.

표:

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년 각 월, 분기 및 연도별로 포함되어 있습니다.

다음과 같은 것이 있는 다른 테이블이 있습니다.

테이블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

표 2의 각 항목에 대해 표 1에 포함되는 가능한 시간 프레임을 찾아야 합니다.

표 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 구간에서 낙하물에 대해 무엇을 의미하는지 정의해야 합니다.

일반적으로 두 가지 해석이 가능합니다.더 제한적인 것은 SubInterval입니다. 즉, 일치된 간격은 기준 간격으로 완전히 덮여 있습니다.

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

두 구간 모두에 공통된 점이 하나 이상 있다는 것을 의미하는 더 완화된 가능성은 교차입니다.

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

그 결정에 따라 다른 가입 조건을 사용하게 됩니다.첫 번째 가능성이 있는 아래 쿼리에서 코멘트를 간단히 바꿔 다른 옵션을 얻습니다.

시뮬레이션된 데이터가 포함된 테이블은 아래에 작성됩니다.

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;

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  

INSTRESS 옵션에 대한 레코드를 훨씬 더 많이 얻을 수 있습니다.

여기 검사 데이터가 있습니다.

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;

간단한 사이가 도움이 될 것입니다.

먼저 두 개의 문장 사이에 있는 문장을 사용하여 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은 다음과 같습니다.

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

첫째, 쿼리에서 변환하지 않도록 모든 것을 표준 DATE 형식으로 저장하면 생활이 훨씬 간단해집니다.그러면 패턴은 간단히 다음과 같습니다.

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

SQL에서 찾은 구간의 교차점을 표현하는 가장 좋은 방법은 다음과 같습니다.

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

교집합의 모든 경우는 다음 두 조건 중 하나에 해당합니다.

뛰어난 성능 없이 아주 간단한 방법을 선택했습니다 =)

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    |-----|

저는 당신이 여기서 무엇을 이루고 싶은지 잘 모르지만, 이것이 당신에게 도움이 되기를 바랍니다.어떻게든 당신이 언급한 (일부) 결과물을 얻을 수 있었습니다.이 코드를 조금만 수정하면 됩니다.

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'

From tbl1, tbl2 where (CONVERT(DATE, tbl2)).START) >= CONVERT (DATE,tbl1).시작) 및 (변환(날짜, tbl2).[END]) <= CONVERT (DATE,tbl1).[END]).

언급URL : https://stackoverflow.com/questions/34184675/find-matching-interval-in-sql-oracle

반응형