안녕하세요. itsqf의 001이란 코드에서 시작 날짜와 끝 날짜 중 날짜가 겹치는 기간은 제외하고 일수를 구하는 쿼리를 작성하고자 합니다. itsqf의 001과 001의 날짜가 겹쳤을 때는 그대로 년차를 구하지만 itsqf의 코드가 같고 겹치는 날짜 제외하고 겹치지 않는 날짜들로만 총 날짜를 구하고자 합니다. WITH tech AS ( SELECT 'AAA' cd, '001' itsqf, '20130101' s_day, '20131231' e_day FROM dual UNION ALL SELECT 'AAA', '001', '20130601', '20160831' FROM dual UNION ALL SELECT 'AAA', '001', '20140101', '20141231' FROM dual UNION ALL SELECT 'AAA', '001', '20140401', '20140531' FROM dual UNION ALL SELECT 'AAA', '001', '20140801', '20141130' FROM dual UNION ALL SELECT 'AAA', '001', '20150101', '20151231' FROM dual UNION ALL SELECT 'AAA', '001', '20160101', '20160331' FROM dual UNION ALL SELECT 'AAA', '001', '20200302', '20200622' FROM dual UNION ALL SELECT 'AAA', '003', '20140613', '20141130' FROM dual UNION ALL SELECT 'AAA', '004', '20161101', '20161201' FROM dual UNION ALL SELECT 'AAA', '005', '20161201', '20190702' FROM dual UNION ALL SELECT 'BBB', '001', '20100201', '20110131' FROM dual UNION ALL SELECT 'BBB', '001', '20100201', '20110708' FROM dual UNION ALL SELECT 'BBB', '001', '20101220', '20110901' FROM dual UNION ALL SELECT 'BBB', '001', '20100301', '20110228' FROM dual UNION ALL SELECT 'BBB', '001', '20110101', '20110901' FROM dual UNION ALL SELECT 'BBB', '002', '20080406', '20080721' FROM dual UNION ALL SELECT 'BBB', '002', '20080912', '20081111' FROM dual UNION ALL SELECT 'BBB', '002', '20081101', '20090721' FROM dual UNION ALL SELECT 'BBB', '002', '20081117', '20081230' FROM dual UNION ALL SELECT 'BBB', '002', '20081117', '20090721' FROM dual ) SELECT NVL(a.y_nm, '합계') y_nm , COUNT(DECODE(b.itsqf, '001', 1)) "001" , COUNT(DECODE(b.itsqf, '002', 1)) "002" , COUNT(DECODE(b.itsqf, '003', 1)) "003" , COUNT(DECODE(b.itsqf, '004', 1)) "004" , COUNT(DECODE(b.itsqf, '005', 1)) "005" FROM (SELECT LEVEL - 1 y , CASE WHEN LEVEL = 1 THEN '1년 미만' WHEN LEVEL = 6 THEN '5년 이상' ELSE (LEVEL-1) || '년' END y_nm FROM dual CONNECT BY LEVEL <= 6 ) a , (SELECT cd , itsqf , LEAST(5, FLOOR(SUM(TO_DATE(e_day, 'yyyymmdd') - TO_DATE(s_day, 'yyyymmdd') + 1) / 365)) y FROM tech GROUP BY cd, itsqf ) b WHERE a.y = b.y(+) GROUP BY ROLLUP((a.y, a.y_nm)) ORDER BY a.y ;
현재 쿼리에서 다른 글들을 참고해서 작성을 해보았으나, 작성이 쉽지가 않아서 도움을 요청하게 되었습니다.
답변주시면 감사하겠습니다.
WITH tech AS ( SELECT 'AAA' cd, '001' itsqf, '20130101' s_day, '20131231' e_day FROM dual UNION ALL SELECT 'AAA', '001', '20130601', '20160831' FROM dual UNION ALL SELECT 'AAA', '001', '20140101', '20141231' FROM dual UNION ALL SELECT 'AAA', '001', '20140401', '20140531' FROM dual UNION ALL SELECT 'AAA', '001', '20140801', '20141130' FROM dual UNION ALL SELECT 'AAA', '001', '20150101', '20151231' FROM dual UNION ALL SELECT 'AAA', '001', '20160101', '20160331' FROM dual UNION ALL SELECT 'AAA', '001', '20200302', '20200622' FROM dual UNION ALL SELECT 'AAA', '003', '20140613', '20141130' FROM dual UNION ALL SELECT 'AAA', '004', '20161101', '20161201' FROM dual UNION ALL SELECT 'AAA', '005', '20161201', '20190702' FROM dual UNION ALL SELECT 'BBB', '001', '20100201', '20110131' FROM dual UNION ALL SELECT 'BBB', '001', '20100201', '20110708' FROM dual UNION ALL SELECT 'BBB', '001', '20101220', '20110901' FROM dual UNION ALL SELECT 'BBB', '001', '20100301', '20110228' FROM dual UNION ALL SELECT 'BBB', '001', '20110101', '20110901' FROM dual UNION ALL SELECT 'BBB', '002', '20080406', '20080721' FROM dual UNION ALL SELECT 'BBB', '002', '20080912', '20081111' FROM dual UNION ALL SELECT 'BBB', '002', '20081101', '20090721' FROM dual UNION ALL SELECT 'BBB', '002', '20081117', '20081230' FROM dual UNION ALL SELECT 'BBB', '002', '20081117', '20090721' FROM dual ) SELECT NVL(a.y_nm, '합계') y_nm , COUNT(DECODE(b.itsqf, '001', 1)) "001" , COUNT(DECODE(b.itsqf, '002', 1)) "002" , COUNT(DECODE(b.itsqf, '003', 1)) "003" , COUNT(DECODE(b.itsqf, '004', 1)) "004" , COUNT(DECODE(b.itsqf, '005', 1)) "005" FROM (SELECT LEVEL - 1 y , CASE WHEN LEVEL = 1 THEN '1년 미만' WHEN LEVEL = 6 THEN '5년 이상' ELSE (LEVEL-1) || '년' END y_nm FROM dual CONNECT BY LEVEL <= 6 ) a , (SELECT cd, itsqf , LEAST(5, FLOOR(SUM(e - s + 1) / 365)) y FROM (SELECT cd, itsqf , TO_DATE(MIN(s_day), 'yyyymmdd') s , TO_DATE(MAX(e_day), 'yyyymmdd') e FROM (SELECT cd, itsqf, s_day, e_day , SUM(flag) OVER(PARTITION BY cd, itsqf ORDER BY s_day, e_day) grp FROM (SELECT cd, itsqf, s_day, e_day , CASE WHEN s_day <= MAX(e_day) OVER(PARTITION BY cd, itsqf ORDER BY s_day, e_day ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) THEN 0 ELSE 1 END flag FROM tech ) ) GROUP BY cd, itsqf, grp ) GROUP BY cd, itsqf ) b WHERE a.y = b.y(+) GROUP BY ROLLUP((a.y, a.y_nm)) ORDER BY a.y ;
쿼리 설명
1. flag : 연속 여부 구하기(연속 0, 불연속 1), 이전 종료일이 시작일보다 크면 불연속
2. grp : flag 를 순차적으로 누적합산하여 구함, 연속인 경우 같은 그룹 번호 생성
3. s ~ e : 연속된 기간을 하나로 그룹핑, GROUP BY cd, itsqf, grp
4. 이후 집계 과정은 질문 쿼리와 동일.