1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 안녕하세요. 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 ; |
현재 쿼리에서 다른 글들을 참고해서 작성을 해보았으나, 작성이 쉽지가 않아서 도움을 요청하게 되었습니다.
답변주시면 감사하겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | 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. 이후 집계 과정은 질문 쿼리와 동일.