구간에서 구간빼기 0 5 926

by 김미현 구간 [2008.09.16 17:16:32]


흐음...어렵네요..이거..
고수님들의 도움이 절실합니다.

제가 원하는 것은 사용기간에서 미적용기간을 뺀 실제 사용기간을 구하는겁니다.
즉 table A - table B = table C를 만들려는 거죠.
data는

[ table A : 사용기간]
사용자 시작일     종료일
갑돌이 20080901   20080910
갑돌이 20080920   20080930
갑순이 20080910   20080915
홍길동 20080910   20080915
홍길동 20080915   20080925
홍길동 20080925   20080930
일지매 20080902   20080930
삼식이 20080915   20080920
삼순이 20080901   20080930

[ table B : 미적용기간]
사용자 시작일     종료일
갑돌이 20080903   20080916
갑돌이 20080923   20080926
갑순이 20080929   20080930
홍길동 20080923   20080925
삼식이 20080901   20080930
삼순이 20080905   20080910
삼순이 20080913   20080917
삼순이 20080921   20090924

[ table C : 실제사용기간]
갑돌이 20080901   20080902
갑돌이 20080927   20080930
갑순이 20080910   20080915
홍길동 20080910   20080922
홍길동 20080926   20080930
일지매 20080902   20080930
삼순이 20080901   20080904
삼순이 20080911   20080912
삼순이 20080918   20080920
삼순이 20090925   20080930

이거 sql로 한번에 뽑을 수 있을까요?

by 호야 [2008.09.16 17:51:06]
아... 제가 봐도 어질 어질 하군요..^^; 저두 3개월 밖에 안 된 사람이라
가상 테이블 (dual_day) 1~31 까지 가상 숫자를 두시구요
2개의 테이블을 Between 조인을 해서 푼 상태로 차집합을 구하시면
날짜별로 나옵니다..-_- 문제는 이놈들을 합치는건데..ㅎㅎㅎ
마농님이 해 주실듯..^ㅡ^;

by 호야 [2008.09.16 19:03:12]
강정식님이 풀어 주신.. 일반 날짜들을 기간으로 분류 하는 쿼리 입니다.

wITH
TAB AS
(
SELECT '멍멍' C1, '20080905' C2 FROM DUAL UNION ALL
SELECT '멍멍' C1, '20080907' C2 FROM DUAL UNION ALL
SELECT '아' C1, '20080902' C2 FROM DUAL UNION ALL
SELECT '아' C1, '20080920' C2 FROM DUAL UNION ALL
SELECT '아' C1, '20080921' C2 FROM DUAL UNION ALL
SELECT '아' C1, '20080922' C2 FROM DUAL UNION ALL
SELECT '아' C1, '20080927' C2 FROM DUAL UNION ALL
SELECT '아' C1, '20080930' C2 FROM DUAL
)
SELECT C1,
MIN(MIN_C2) MIN_DAY,
MIN(MAX_C2) MAX_DAY
FROM (SELECT C1,
C2,
MIN(C2) OVER(PARTITION BY C1, GUBN) MIN_C2,
MAX(C2) OVER(PARTITION BY C1, GUBN) MAX_C2,
GUBN
FROM (SELECT C1,
C2,
SUM(FLAG) OVER(ORDER BY C2) GUBN
FROM (SELECT C1,
C2,
LAG(C2) OVER(PARTITION BY C1 ORDER BY C2),
TO_NUMBER(C2) - TO_NUMBER(LAG(C2) OVER(PARTITION BY C1 ORDER BY C2)),
DECODE(TO_NUMBER(C2) - TO_NUMBER(LAG(C2) OVER(PARTITION BY C1 ORDER BY C2)), 1, 0, 1) FLA
FROM TAB)))
GROUP BY C1, GUBN

by 호야 [2008.09.16 19:05:57]
테이블 te1 : 사용기간
te2 : 미적용기간
dual_day : 1~ 31 까지 있는 테이블

select name,substr(a.startdate,1,6)||lpad(b.lv,2,'0') day
from te1 a, dual_day b
where lv between substr(startdate,7,2) and substr(enddate,7,2)
minus
select name,substr(a.startdate,1,6)||lpad(b.lv,2,'0') day
from te2 a, dual_day b
where lv between substr(startdate,7,2) and substr(enddate,7,2)

결과는 위에 정식님이 풀어준 WITH 절에 있는 넘들 처럼 나옵니다

이 두놈을 합치면..-_- 풀어 질듯합니다.. 강정식형님 짱짱짱..ㅠ..ㅠ 멋져요

by 산노을 [2008.09.16 19:41:25]
- 사용기간이 중복되지 않고 미적용기간이 중복되지 않는 조건하에
아래의 Query 로 되지 않을까요?

SELECT A.NAME,
A.START_DATE,
A.END_DATE
FROM A
WHERE NOT EXISTS (SELECT 1
FROM B
WHERE B.NAME = A.NAME
AND (B.START_DATE BETWEEN A.START_DATE AND A.END_DATE
OR B.END_DATE BETWEEN A.START_DATE AND A.END_DATE) )
UNION ALL
SELECT A.NAME,
NVL( (SELECT to_char(to_date(MAX(B.END_DATE), 'yyyymmdd') + 1, 'yyyymmdd')
FROM B
WHERE B.NAME = A.NAME
AND B.END_DATE > A.START_DATE
AND B.END_DATE < A.END_DATE) , A.START_DATE) as START_DATE,
A.END_DATE
FROM (SELECT A.NAME,
A.START_DATE,
to_char(to_date(B.START_DATE, 'yyyymmdd') - 1, 'yyyymmdd') as END_DATE
FROM A, B
WHERE B.NAME = A.NAME
AND B.START_DATE > A.START_DATE
AND B.START_DATE < A.END_DATE) A
UNION ALL
SELECT A.NAME,
A.START_DATE,
NVL( (SELECT to_char(to_date(MAX(B.START_DATE), 'yyyymmdd') - 1, 'yyyymmdd')
FROM B
WHERE B.NAME = A.NAME
AND B.END_DATE > A.START_DATE
AND B.END_DATE < A.END_DATE) , A.END_DATE) as END_DATE
FROM (SELECT A.NAME,
to_char(to_date(B.END_DATE, 'yyyymmdd') + 1, 'yyyymmdd') as START_DATE,
B.END_DATE
FROM A, B
WHERE B.NAME = A.NAME
AND B.END_DATE > A.START_DATE
AND B.END_DATE < A.END_DATE) A
ORDER BY 1,2

by 산노을 [2008.09.16 21:02:17]
테스트 안하고 코딩만 했더니 문제가 많았네요.
이번에는 되지 않을까요?

-- 미적용기간이 없는 사용기간
SELECT A.NAME,
A.START_DATE,
A.END_DATE
FROM A
WHERE NOT EXISTS (SELECT 1
FROM B
WHERE B.NAME = A.NAME
AND (B.START_DATE BETWEEN A.START_DATE AND A.END_DATE
OR B.END_DATE BETWEEN A.START_DATE AND A.END_DATE
OR (B.START_DATE < A.START_DATE AND B.END_DATE > A.START_DATE)
OR (B.END_DATE > A.END_DATE AND B.START_DATE < A.END_DATE)) )
UNION ALL
-- 미적용기간을 제외한 사용기간 (미적용기간 시작일기준)
SELECT A.NAME,
nvl( (SELECT to_char(to_date(max(B.END_DATE), 'yyyymmdd') + 1, 'yyyymmdd')
FROM B
WHERE B.NAME = A.NAME
AND B.END_DATE > A.START_DATE
AND B.END_DATE < A.END_DATE) , A.START_DATE) as START_DATE,
A.END_DATE
FROM (SELECT A.NAME,
A.START_DATE,
to_char(to_date(B.START_DATE, 'yyyymmdd') - 1, 'yyyymmdd') as END_DATE
FROM A, B
WHERE B.NAME = A.NAME
AND B.START_DATE > A.START_DATE
AND B.START_DATE < A.END_DATE) A
UNION ALL
-- 미적용기간을 제외한 사용기간 (미적용기간 마지막 종료일기준)
SELECT A.NAME,
A.START_DATE,
A.END_DATE
FROM (SELECT A.NAME,
to_char(to_date(B.END_DATE, 'yyyymmdd') + 1, 'yyyymmdd') as START_DATE,
A.END_DATE
FROM A, B
WHERE B.NAME = A.NAME
AND B.END_DATE > A.START_DATE
AND B.END_DATE < A.END_DATE) A
WHERE NOT EXISTS (SELECT 1
FROM B
WHERE B.NAME = A.NAME
AND B.START_DATE > A.START_DATE
AND B.START_DATE < A.END_DATE)
ORDER BY 1,2
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입